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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. ccxt/__init__.py +358 -0
  2. ccxt/abantether.py +316 -0
  3. ccxt/abstract/__init__.py +0 -0
  4. ccxt/abstract/abantether.py +5 -0
  5. ccxt/abstract/ace.py +15 -0
  6. ccxt/abstract/afratether.py +6 -0
  7. ccxt/abstract/alpaca.py +70 -0
  8. ccxt/abstract/arzinja.py +5 -0
  9. ccxt/abstract/arzplus.py +7 -0
  10. ccxt/abstract/ascendex.py +77 -0
  11. ccxt/abstract/bequant.py +115 -0
  12. ccxt/abstract/bigone.py +45 -0
  13. ccxt/abstract/binance.py +712 -0
  14. ccxt/abstract/binancecoinm.py +712 -0
  15. ccxt/abstract/binanceus.py +764 -0
  16. ccxt/abstract/binanceusdm.py +712 -0
  17. ccxt/abstract/bingx.py +113 -0
  18. ccxt/abstract/bit2c.py +27 -0
  19. ccxt/abstract/bitbank.py +27 -0
  20. ccxt/abstract/bitbay.py +53 -0
  21. ccxt/abstract/bitbns.py +40 -0
  22. ccxt/abstract/bitcoincom.py +115 -0
  23. ccxt/abstract/bitfinex.py +69 -0
  24. ccxt/abstract/bitfinex2.py +139 -0
  25. ccxt/abstract/bitflyer.py +38 -0
  26. ccxt/abstract/bitget.py +508 -0
  27. ccxt/abstract/bithumb.py +32 -0
  28. ccxt/abstract/bitimen.py +7 -0
  29. ccxt/abstract/bitir.py +7 -0
  30. ccxt/abstract/bitmart.py +99 -0
  31. ccxt/abstract/bitmex.py +97 -0
  32. ccxt/abstract/bitopro.py +29 -0
  33. ccxt/abstract/bitpanda.py +35 -0
  34. ccxt/abstract/bitpin.py +7 -0
  35. ccxt/abstract/bitrue.py +72 -0
  36. ccxt/abstract/bitso.py +43 -0
  37. ccxt/abstract/bitstamp.py +258 -0
  38. ccxt/abstract/bitteam.py +29 -0
  39. ccxt/abstract/bitvavo.py +27 -0
  40. ccxt/abstract/bl3p.py +19 -0
  41. ccxt/abstract/blockchaincom.py +28 -0
  42. ccxt/abstract/blofin.py +37 -0
  43. ccxt/abstract/btcalpha.py +18 -0
  44. ccxt/abstract/btcbox.py +13 -0
  45. ccxt/abstract/btcmarkets.py +39 -0
  46. ccxt/abstract/btcturk.py +20 -0
  47. ccxt/abstract/bybit.py +298 -0
  48. ccxt/abstract/cex.py +33 -0
  49. ccxt/abstract/coinbase.py +94 -0
  50. ccxt/abstract/coinbaseadvanced.py +94 -0
  51. ccxt/abstract/coinbaseexchange.py +67 -0
  52. ccxt/abstract/coinbaseinternational.py +39 -0
  53. ccxt/abstract/coincatch.py +94 -0
  54. ccxt/abstract/coincheck.py +33 -0
  55. ccxt/abstract/coinex.py +237 -0
  56. ccxt/abstract/coinlist.py +54 -0
  57. ccxt/abstract/coinmate.py +62 -0
  58. ccxt/abstract/coinmetro.py +34 -0
  59. ccxt/abstract/coinone.py +67 -0
  60. ccxt/abstract/coinsph.py +54 -0
  61. ccxt/abstract/coinspot.py +28 -0
  62. ccxt/abstract/cryptocom.py +107 -0
  63. ccxt/abstract/currencycom.py +68 -0
  64. ccxt/abstract/delta.py +50 -0
  65. ccxt/abstract/deribit.py +125 -0
  66. ccxt/abstract/digifinex.py +91 -0
  67. ccxt/abstract/eterex.py +5 -0
  68. ccxt/abstract/excoino.py +7 -0
  69. ccxt/abstract/exir.py +8 -0
  70. ccxt/abstract/exmo.py +55 -0
  71. ccxt/abstract/exnovin.py +6 -0
  72. ccxt/abstract/farhadexchange.py +5 -0
  73. ccxt/abstract/fmfwio.py +115 -0
  74. ccxt/abstract/gate.py +265 -0
  75. ccxt/abstract/gateio.py +265 -0
  76. ccxt/abstract/gemini.py +58 -0
  77. ccxt/abstract/hashkey.py +67 -0
  78. ccxt/abstract/hitbtc.py +115 -0
  79. ccxt/abstract/hitbtc3.py +115 -0
  80. ccxt/abstract/hitobit.py +8 -0
  81. ccxt/abstract/hollaex.py +33 -0
  82. ccxt/abstract/htx.py +548 -0
  83. ccxt/abstract/huobi.py +548 -0
  84. ccxt/abstract/huobijp.py +114 -0
  85. ccxt/abstract/hyperliquid.py +6 -0
  86. ccxt/abstract/idex.py +26 -0
  87. ccxt/abstract/independentreserve.py +37 -0
  88. ccxt/abstract/indodax.py +26 -0
  89. ccxt/abstract/jibitex.py +7 -0
  90. ccxt/abstract/kraken.py +57 -0
  91. ccxt/abstract/krakenfutures.py +38 -0
  92. ccxt/abstract/kucoin.py +214 -0
  93. ccxt/abstract/kucoinfutures.py +233 -0
  94. ccxt/abstract/kuna.py +182 -0
  95. ccxt/abstract/latoken.py +56 -0
  96. ccxt/abstract/lbank.py +61 -0
  97. ccxt/abstract/luno.py +37 -0
  98. ccxt/abstract/lykke.py +29 -0
  99. ccxt/abstract/mercado.py +25 -0
  100. ccxt/abstract/mexc.py +178 -0
  101. ccxt/abstract/ndax.py +97 -0
  102. ccxt/abstract/nobitex.py +7 -0
  103. ccxt/abstract/novadax.py +29 -0
  104. ccxt/abstract/oceanex.py +22 -0
  105. ccxt/abstract/okcoin.py +74 -0
  106. ccxt/abstract/okexchange.py +8 -0
  107. ccxt/abstract/okx.py +324 -0
  108. ccxt/abstract/ompfinex.py +7 -0
  109. ccxt/abstract/onetrading.py +35 -0
  110. ccxt/abstract/oxfun.py +34 -0
  111. ccxt/abstract/p2b.py +22 -0
  112. ccxt/abstract/paradex.py +40 -0
  113. ccxt/abstract/paymium.py +28 -0
  114. ccxt/abstract/phemex.py +115 -0
  115. ccxt/abstract/poloniex.py +69 -0
  116. ccxt/abstract/poloniexfutures.py +48 -0
  117. ccxt/abstract/probit.py +23 -0
  118. ccxt/abstract/ramzinex.py +7 -0
  119. ccxt/abstract/sarmayex.py +5 -0
  120. ccxt/abstract/sarrafex.py +7 -0
  121. ccxt/abstract/tabdeal.py +7 -0
  122. ccxt/abstract/tetherland.py +5 -0
  123. ccxt/abstract/timex.py +62 -0
  124. ccxt/abstract/tokocrypto.py +37 -0
  125. ccxt/abstract/tradeogre.py +16 -0
  126. ccxt/abstract/twox.py +5 -0
  127. ccxt/abstract/ubitex.py +7 -0
  128. ccxt/abstract/upbit.py +38 -0
  129. ccxt/abstract/vertex.py +19 -0
  130. ccxt/abstract/wallex.py +8 -0
  131. ccxt/abstract/wavesexchange.py +154 -0
  132. ccxt/abstract/wazirx.py +30 -0
  133. ccxt/abstract/whitebit.py +98 -0
  134. ccxt/abstract/woo.py +83 -0
  135. ccxt/abstract/woofipro.py +119 -0
  136. ccxt/abstract/xt.py +152 -0
  137. ccxt/abstract/yobit.py +16 -0
  138. ccxt/abstract/zaif.py +38 -0
  139. ccxt/abstract/zonda.py +53 -0
  140. ccxt/ace.py +1012 -0
  141. ccxt/afratether.py +293 -0
  142. ccxt/alpaca.py +1083 -0
  143. ccxt/arzinja.py +285 -0
  144. ccxt/arzplus.py +412 -0
  145. ccxt/ascendex.py +3330 -0
  146. ccxt/async_support/__init__.py +337 -0
  147. ccxt/async_support/abantether.py +316 -0
  148. ccxt/async_support/ace.py +1012 -0
  149. ccxt/async_support/afratether.py +293 -0
  150. ccxt/async_support/alpaca.py +1083 -0
  151. ccxt/async_support/arzinja.py +285 -0
  152. ccxt/async_support/arzplus.py +412 -0
  153. ccxt/async_support/ascendex.py +3330 -0
  154. ccxt/async_support/base/__init__.py +1 -0
  155. ccxt/async_support/base/exchange.py +1966 -0
  156. ccxt/async_support/base/throttler.py +50 -0
  157. ccxt/async_support/base/ws/__init__.py +38 -0
  158. ccxt/async_support/base/ws/aiohttp_client.py +125 -0
  159. ccxt/async_support/base/ws/cache.py +212 -0
  160. ccxt/async_support/base/ws/client.py +193 -0
  161. ccxt/async_support/base/ws/fast_client.py +96 -0
  162. ccxt/async_support/base/ws/functions.py +59 -0
  163. ccxt/async_support/base/ws/future.py +58 -0
  164. ccxt/async_support/base/ws/order_book.py +78 -0
  165. ccxt/async_support/base/ws/order_book_side.py +174 -0
  166. ccxt/async_support/bequant.py +33 -0
  167. ccxt/async_support/bigone.py +2113 -0
  168. ccxt/async_support/binance.py +12234 -0
  169. ccxt/async_support/binancecoinm.py +45 -0
  170. ccxt/async_support/binanceus.py +211 -0
  171. ccxt/async_support/binanceusdm.py +58 -0
  172. ccxt/async_support/bingx.py +4325 -0
  173. ccxt/async_support/bit2c.py +866 -0
  174. ccxt/async_support/bitbank.py +1001 -0
  175. ccxt/async_support/bitbay.py +17 -0
  176. ccxt/async_support/bitbns.py +1154 -0
  177. ccxt/async_support/bitcoincom.py +17 -0
  178. ccxt/async_support/bitfinex.py +1617 -0
  179. ccxt/async_support/bitfinex2.py +3552 -0
  180. ccxt/async_support/bitflyer.py +995 -0
  181. ccxt/async_support/bitget.py +8273 -0
  182. ccxt/async_support/bithumb.py +1061 -0
  183. ccxt/async_support/bitimen.py +401 -0
  184. ccxt/async_support/bitir.py +490 -0
  185. ccxt/async_support/bitmart.py +4415 -0
  186. ccxt/async_support/bitmex.py +2756 -0
  187. ccxt/async_support/bitopro.py +1630 -0
  188. ccxt/async_support/bitpanda.py +16 -0
  189. ccxt/async_support/bitpin.py +454 -0
  190. ccxt/async_support/bitrue.py +3027 -0
  191. ccxt/async_support/bitso.py +1670 -0
  192. ccxt/async_support/bitstamp.py +2203 -0
  193. ccxt/async_support/bitteam.py +2239 -0
  194. ccxt/async_support/bitvavo.py +1968 -0
  195. ccxt/async_support/bl3p.py +485 -0
  196. ccxt/async_support/blockchaincom.py +1104 -0
  197. ccxt/async_support/blofin.py +2066 -0
  198. ccxt/async_support/btcalpha.py +891 -0
  199. ccxt/async_support/btcbox.py +544 -0
  200. ccxt/async_support/btcmarkets.py +1221 -0
  201. ccxt/async_support/btcturk.py +911 -0
  202. ccxt/async_support/bybit.py +8159 -0
  203. ccxt/async_support/cex.py +1605 -0
  204. ccxt/async_support/coinbase.py +4475 -0
  205. ccxt/async_support/coinbaseadvanced.py +17 -0
  206. ccxt/async_support/coinbaseexchange.py +1734 -0
  207. ccxt/async_support/coinbaseinternational.py +1899 -0
  208. ccxt/async_support/coincatch.py +5069 -0
  209. ccxt/async_support/coincheck.py +815 -0
  210. ccxt/async_support/coinex.py +5526 -0
  211. ccxt/async_support/coinlist.py +2243 -0
  212. ccxt/async_support/coinmate.py +1067 -0
  213. ccxt/async_support/coinmetro.py +1797 -0
  214. ccxt/async_support/coinone.py +1127 -0
  215. ccxt/async_support/coinsph.py +1850 -0
  216. ccxt/async_support/coinspot.py +534 -0
  217. ccxt/async_support/cryptocom.py +2822 -0
  218. ccxt/async_support/currencycom.py +1950 -0
  219. ccxt/async_support/delta.py +3376 -0
  220. ccxt/async_support/deribit.py +3437 -0
  221. ccxt/async_support/digifinex.py +3960 -0
  222. ccxt/async_support/eterex.py +286 -0
  223. ccxt/async_support/excoino.py +399 -0
  224. ccxt/async_support/exir.py +375 -0
  225. ccxt/async_support/exmo.py +2462 -0
  226. ccxt/async_support/exnovin.py +360 -0
  227. ccxt/async_support/farhadexchange.py +266 -0
  228. ccxt/async_support/fmfwio.py +34 -0
  229. ccxt/async_support/gate.py +6976 -0
  230. ccxt/async_support/gateio.py +16 -0
  231. ccxt/async_support/gemini.py +1825 -0
  232. ccxt/async_support/hashkey.py +4150 -0
  233. ccxt/async_support/hitbtc.py +3423 -0
  234. ccxt/async_support/hitbtc3.py +16 -0
  235. ccxt/async_support/hitobit.py +391 -0
  236. ccxt/async_support/hollaex.py +1813 -0
  237. ccxt/async_support/htx.py +8506 -0
  238. ccxt/async_support/huobi.py +16 -0
  239. ccxt/async_support/huobijp.py +1801 -0
  240. ccxt/async_support/hyperliquid.py +2431 -0
  241. ccxt/async_support/idex.py +1766 -0
  242. ccxt/async_support/independentreserve.py +784 -0
  243. ccxt/async_support/indodax.py +1247 -0
  244. ccxt/async_support/jibitex.py +395 -0
  245. ccxt/async_support/kraken.py +2894 -0
  246. ccxt/async_support/krakenfutures.py +2601 -0
  247. ccxt/async_support/kucoin.py +4602 -0
  248. ccxt/async_support/kucoinfutures.py +2698 -0
  249. ccxt/async_support/kuna.py +1841 -0
  250. ccxt/async_support/latoken.py +1664 -0
  251. ccxt/async_support/lbank.py +2683 -0
  252. ccxt/async_support/luno.py +1067 -0
  253. ccxt/async_support/lykke.py +1270 -0
  254. ccxt/async_support/mercado.py +842 -0
  255. ccxt/async_support/mexc.py +5369 -0
  256. ccxt/async_support/ndax.py +2354 -0
  257. ccxt/async_support/nobitex.py +419 -0
  258. ccxt/async_support/novadax.py +1484 -0
  259. ccxt/async_support/oceanex.py +903 -0
  260. ccxt/async_support/okcoin.py +2936 -0
  261. ccxt/async_support/okexchange.py +349 -0
  262. ccxt/async_support/okx.py +7827 -0
  263. ccxt/async_support/ompfinex.py +472 -0
  264. ccxt/async_support/onetrading.py +1911 -0
  265. ccxt/async_support/oxfun.py +2773 -0
  266. ccxt/async_support/p2b.py +1194 -0
  267. ccxt/async_support/paradex.py +2015 -0
  268. ccxt/async_support/paymium.py +564 -0
  269. ccxt/async_support/phemex.py +4473 -0
  270. ccxt/async_support/poloniex.py +2232 -0
  271. ccxt/async_support/poloniexfutures.py +1717 -0
  272. ccxt/async_support/probit.py +1734 -0
  273. ccxt/async_support/ramzinex.py +476 -0
  274. ccxt/async_support/sarmayex.py +357 -0
  275. ccxt/async_support/sarrafex.py +478 -0
  276. ccxt/async_support/tabdeal.py +364 -0
  277. ccxt/async_support/tetherland.py +349 -0
  278. ccxt/async_support/timex.py +1593 -0
  279. ccxt/async_support/tokocrypto.py +2405 -0
  280. ccxt/async_support/tradeogre.py +608 -0
  281. ccxt/async_support/twox.py +326 -0
  282. ccxt/async_support/ubitex.py +409 -0
  283. ccxt/async_support/upbit.py +1833 -0
  284. ccxt/async_support/vertex.py +2922 -0
  285. ccxt/async_support/wallex.py +445 -0
  286. ccxt/async_support/wavesexchange.py +2473 -0
  287. ccxt/async_support/wazirx.py +1224 -0
  288. ccxt/async_support/whitebit.py +2469 -0
  289. ccxt/async_support/woo.py +3114 -0
  290. ccxt/async_support/woofipro.py +2533 -0
  291. ccxt/async_support/xt.py +4454 -0
  292. ccxt/async_support/yobit.py +1283 -0
  293. ccxt/async_support/zaif.py +725 -0
  294. ccxt/async_support/zonda.py +1828 -0
  295. ccxt/base/__init__.py +27 -0
  296. ccxt/base/decimal_to_precision.py +174 -0
  297. ccxt/base/errors.py +242 -0
  298. ccxt/base/exchange.py +5941 -0
  299. ccxt/base/precise.py +287 -0
  300. ccxt/base/types.py +502 -0
  301. ccxt/bequant.py +33 -0
  302. ccxt/bigone.py +2112 -0
  303. ccxt/binance.py +12233 -0
  304. ccxt/binancecoinm.py +45 -0
  305. ccxt/binanceus.py +211 -0
  306. ccxt/binanceusdm.py +58 -0
  307. ccxt/bingx.py +4324 -0
  308. ccxt/bit2c.py +866 -0
  309. ccxt/bitbank.py +1001 -0
  310. ccxt/bitbay.py +17 -0
  311. ccxt/bitbns.py +1154 -0
  312. ccxt/bitcoincom.py +17 -0
  313. ccxt/bitfinex.py +1617 -0
  314. ccxt/bitfinex2.py +3552 -0
  315. ccxt/bitflyer.py +995 -0
  316. ccxt/bitget.py +8272 -0
  317. ccxt/bithumb.py +1061 -0
  318. ccxt/bitimen.py +401 -0
  319. ccxt/bitir.py +490 -0
  320. ccxt/bitmart.py +4415 -0
  321. ccxt/bitmex.py +2756 -0
  322. ccxt/bitopro.py +1630 -0
  323. ccxt/bitpanda.py +16 -0
  324. ccxt/bitpin.py +454 -0
  325. ccxt/bitrue.py +3026 -0
  326. ccxt/bitso.py +1670 -0
  327. ccxt/bitstamp.py +2203 -0
  328. ccxt/bitteam.py +2239 -0
  329. ccxt/bitvavo.py +1968 -0
  330. ccxt/bl3p.py +485 -0
  331. ccxt/blockchaincom.py +1104 -0
  332. ccxt/blofin.py +2066 -0
  333. ccxt/btcalpha.py +891 -0
  334. ccxt/btcbox.py +544 -0
  335. ccxt/btcmarkets.py +1221 -0
  336. ccxt/btcturk.py +911 -0
  337. ccxt/bybit.py +8158 -0
  338. ccxt/cex.py +1605 -0
  339. ccxt/coinbase.py +4474 -0
  340. ccxt/coinbaseadvanced.py +17 -0
  341. ccxt/coinbaseexchange.py +1734 -0
  342. ccxt/coinbaseinternational.py +1899 -0
  343. ccxt/coincatch.py +5069 -0
  344. ccxt/coincheck.py +815 -0
  345. ccxt/coinex.py +5525 -0
  346. ccxt/coinlist.py +2243 -0
  347. ccxt/coinmate.py +1067 -0
  348. ccxt/coinmetro.py +1797 -0
  349. ccxt/coinone.py +1127 -0
  350. ccxt/coinsph.py +1850 -0
  351. ccxt/coinspot.py +534 -0
  352. ccxt/cryptocom.py +2822 -0
  353. ccxt/currencycom.py +1950 -0
  354. ccxt/delta.py +3376 -0
  355. ccxt/deribit.py +3437 -0
  356. ccxt/digifinex.py +3959 -0
  357. ccxt/eterex.py +286 -0
  358. ccxt/excoino.py +399 -0
  359. ccxt/exir.py +375 -0
  360. ccxt/exmo.py +2462 -0
  361. ccxt/exnovin.py +360 -0
  362. ccxt/farhadexchange.py +266 -0
  363. ccxt/fmfwio.py +34 -0
  364. ccxt/gate.py +6975 -0
  365. ccxt/gateio.py +16 -0
  366. ccxt/gemini.py +1824 -0
  367. ccxt/hashkey.py +4150 -0
  368. ccxt/hitbtc.py +3423 -0
  369. ccxt/hitbtc3.py +16 -0
  370. ccxt/hitobit.py +391 -0
  371. ccxt/hollaex.py +1813 -0
  372. ccxt/htx.py +8505 -0
  373. ccxt/huobi.py +16 -0
  374. ccxt/huobijp.py +1801 -0
  375. ccxt/hyperliquid.py +2430 -0
  376. ccxt/idex.py +1766 -0
  377. ccxt/independentreserve.py +784 -0
  378. ccxt/indodax.py +1247 -0
  379. ccxt/jibitex.py +395 -0
  380. ccxt/kraken.py +2894 -0
  381. ccxt/krakenfutures.py +2601 -0
  382. ccxt/kucoin.py +4601 -0
  383. ccxt/kucoinfutures.py +2698 -0
  384. ccxt/kuna.py +1841 -0
  385. ccxt/latoken.py +1664 -0
  386. ccxt/lbank.py +2682 -0
  387. ccxt/luno.py +1067 -0
  388. ccxt/lykke.py +1270 -0
  389. ccxt/mercado.py +842 -0
  390. ccxt/mexc.py +5369 -0
  391. ccxt/ndax.py +2354 -0
  392. ccxt/nobitex.py +419 -0
  393. ccxt/novadax.py +1484 -0
  394. ccxt/oceanex.py +903 -0
  395. ccxt/okcoin.py +2936 -0
  396. ccxt/okexchange.py +349 -0
  397. ccxt/okx.py +7826 -0
  398. ccxt/ompfinex.py +472 -0
  399. ccxt/onetrading.py +1911 -0
  400. ccxt/oxfun.py +2772 -0
  401. ccxt/p2b.py +1194 -0
  402. ccxt/paradex.py +2015 -0
  403. ccxt/paymium.py +564 -0
  404. ccxt/phemex.py +4473 -0
  405. ccxt/poloniex.py +2232 -0
  406. ccxt/poloniexfutures.py +1717 -0
  407. ccxt/pro/__init__.py +149 -0
  408. ccxt/pro/alpaca.py +685 -0
  409. ccxt/pro/ascendex.py +916 -0
  410. ccxt/pro/bequant.py +38 -0
  411. ccxt/pro/binance.py +3488 -0
  412. ccxt/pro/binancecoinm.py +28 -0
  413. ccxt/pro/binanceus.py +48 -0
  414. ccxt/pro/binanceusdm.py +31 -0
  415. ccxt/pro/bingx.py +1264 -0
  416. ccxt/pro/bitcoincom.py +34 -0
  417. ccxt/pro/bitfinex.py +621 -0
  418. ccxt/pro/bitfinex2.py +1083 -0
  419. ccxt/pro/bitget.py +1692 -0
  420. ccxt/pro/bithumb.py +368 -0
  421. ccxt/pro/bitmart.py +1449 -0
  422. ccxt/pro/bitmex.py +1656 -0
  423. ccxt/pro/bitopro.py +445 -0
  424. ccxt/pro/bitpanda.py +15 -0
  425. ccxt/pro/bitrue.py +447 -0
  426. ccxt/pro/bitstamp.py +522 -0
  427. ccxt/pro/bitvavo.py +1270 -0
  428. ccxt/pro/blockchaincom.py +738 -0
  429. ccxt/pro/blofin.py +692 -0
  430. ccxt/pro/bybit.py +2000 -0
  431. ccxt/pro/cex.py +1440 -0
  432. ccxt/pro/coinbase.py +678 -0
  433. ccxt/pro/coinbaseadvanced.py +16 -0
  434. ccxt/pro/coinbaseexchange.py +895 -0
  435. ccxt/pro/coinbaseinternational.py +620 -0
  436. ccxt/pro/coincatch.py +1464 -0
  437. ccxt/pro/coincheck.py +199 -0
  438. ccxt/pro/coinex.py +1061 -0
  439. ccxt/pro/coinone.py +395 -0
  440. ccxt/pro/cryptocom.py +947 -0
  441. ccxt/pro/currencycom.py +536 -0
  442. ccxt/pro/deribit.py +892 -0
  443. ccxt/pro/exmo.py +629 -0
  444. ccxt/pro/gate.py +1416 -0
  445. ccxt/pro/gateio.py +15 -0
  446. ccxt/pro/gemini.py +865 -0
  447. ccxt/pro/hashkey.py +802 -0
  448. ccxt/pro/hitbtc.py +1216 -0
  449. ccxt/pro/hollaex.py +563 -0
  450. ccxt/pro/htx.py +2215 -0
  451. ccxt/pro/huobi.py +15 -0
  452. ccxt/pro/huobijp.py +570 -0
  453. ccxt/pro/hyperliquid.py +525 -0
  454. ccxt/pro/idex.py +672 -0
  455. ccxt/pro/independentreserve.py +270 -0
  456. ccxt/pro/kraken.py +1356 -0
  457. ccxt/pro/krakenfutures.py +1492 -0
  458. ccxt/pro/kucoin.py +1133 -0
  459. ccxt/pro/kucoinfutures.py +1081 -0
  460. ccxt/pro/lbank.py +843 -0
  461. ccxt/pro/luno.py +303 -0
  462. ccxt/pro/mexc.py +1122 -0
  463. ccxt/pro/ndax.py +506 -0
  464. ccxt/pro/okcoin.py +698 -0
  465. ccxt/pro/okx.py +1851 -0
  466. ccxt/pro/onetrading.py +1275 -0
  467. ccxt/pro/oxfun.py +950 -0
  468. ccxt/pro/p2b.py +419 -0
  469. ccxt/pro/paradex.py +352 -0
  470. ccxt/pro/phemex.py +1441 -0
  471. ccxt/pro/poloniex.py +1166 -0
  472. ccxt/pro/poloniexfutures.py +990 -0
  473. ccxt/pro/probit.py +551 -0
  474. ccxt/pro/upbit.py +520 -0
  475. ccxt/pro/vertex.py +943 -0
  476. ccxt/pro/wazirx.py +749 -0
  477. ccxt/pro/whitebit.py +864 -0
  478. ccxt/pro/woo.py +1078 -0
  479. ccxt/pro/woofipro.py +1183 -0
  480. ccxt/pro/xt.py +1067 -0
  481. ccxt/probit.py +1734 -0
  482. ccxt/ramzinex.py +476 -0
  483. ccxt/sarmayex.py +357 -0
  484. ccxt/sarrafex.py +478 -0
  485. ccxt/static_dependencies/__init__.py +1 -0
  486. ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  487. ccxt/static_dependencies/ecdsa/_version.py +520 -0
  488. ccxt/static_dependencies/ecdsa/curves.py +56 -0
  489. ccxt/static_dependencies/ecdsa/der.py +221 -0
  490. ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  491. ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  492. ccxt/static_dependencies/ecdsa/keys.py +332 -0
  493. ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  494. ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  495. ccxt/static_dependencies/ecdsa/util.py +266 -0
  496. ccxt/static_dependencies/ethereum/__init__.py +7 -0
  497. ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  498. ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  499. ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  500. ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  501. ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  502. ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  503. ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  504. ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  505. ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  506. ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  507. ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  508. ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  509. ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  510. ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  511. ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  512. ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  513. ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  514. ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  515. ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  516. ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  517. ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  518. ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  519. ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  520. ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  521. ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  522. ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  523. ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  524. ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  525. ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  526. ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  527. ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  528. ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  529. ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  530. ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  531. ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  532. ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  533. ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  534. ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  535. ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  536. ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  537. ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  538. ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  539. ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  540. ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  541. ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  542. ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  543. ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  544. ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  545. ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  546. ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  547. ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  548. ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  549. ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  550. ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  551. ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  552. ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  553. ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  554. ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  555. ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  556. ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  557. ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  558. ccxt/static_dependencies/keccak/__init__.py +3 -0
  559. ccxt/static_dependencies/keccak/keccak.py +197 -0
  560. ccxt/static_dependencies/lark/__init__.py +38 -0
  561. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  562. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  563. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  564. ccxt/static_dependencies/lark/common.py +86 -0
  565. ccxt/static_dependencies/lark/exceptions.py +292 -0
  566. ccxt/static_dependencies/lark/grammar.py +130 -0
  567. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  568. ccxt/static_dependencies/lark/indenter.py +143 -0
  569. ccxt/static_dependencies/lark/lark.py +658 -0
  570. ccxt/static_dependencies/lark/lexer.py +678 -0
  571. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  572. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  573. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  574. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  575. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  576. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  577. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  578. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  579. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  580. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  581. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  582. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  583. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  584. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  585. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  586. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  587. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  588. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  589. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  590. ccxt/static_dependencies/lark/tree.py +267 -0
  591. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  592. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  593. ccxt/static_dependencies/lark/utils.py +343 -0
  594. ccxt/static_dependencies/lark/visitors.py +596 -0
  595. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  596. ccxt/static_dependencies/marshmallow/base.py +65 -0
  597. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  598. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  599. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  600. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  601. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  602. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  603. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  604. ccxt/static_dependencies/marshmallow/types.py +12 -0
  605. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  606. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  607. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  608. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  609. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  610. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  611. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  612. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  613. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  614. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  615. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  616. ccxt/static_dependencies/msgpack/__init__.py +55 -0
  617. ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  618. ccxt/static_dependencies/msgpack/ext.py +168 -0
  619. ccxt/static_dependencies/msgpack/fallback.py +951 -0
  620. ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  621. ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  622. ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  623. ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  624. ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  625. ccxt/static_dependencies/parsimonious/utils.py +40 -0
  626. ccxt/static_dependencies/starknet/__init__.py +0 -0
  627. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  628. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  629. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  630. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  631. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  632. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  633. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  634. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  635. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  636. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  637. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  638. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  639. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  640. ccxt/static_dependencies/starknet/common.py +15 -0
  641. ccxt/static_dependencies/starknet/constants.py +39 -0
  642. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  643. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  644. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  645. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  646. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  647. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  648. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  649. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  650. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  651. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  652. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  653. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  654. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  655. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  656. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  657. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  658. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  659. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  660. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  661. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  662. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  663. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  664. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  665. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  666. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  667. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  668. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  669. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  670. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  671. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  672. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  673. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  674. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  675. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  676. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  677. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  678. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  679. ccxt/static_dependencies/starkware/__init__.py +0 -0
  680. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  681. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  682. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  683. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  684. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  685. ccxt/static_dependencies/sympy/__init__.py +0 -0
  686. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  687. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  688. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  689. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  690. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  691. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  692. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  693. ccxt/static_dependencies/toolz/__init__.py +26 -0
  694. ccxt/static_dependencies/toolz/_signatures.py +784 -0
  695. ccxt/static_dependencies/toolz/_version.py +520 -0
  696. ccxt/static_dependencies/toolz/compatibility.py +30 -0
  697. ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  698. ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  699. ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  700. ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  701. ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  702. ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  703. ccxt/static_dependencies/toolz/recipes.py +46 -0
  704. ccxt/static_dependencies/toolz/utils.py +9 -0
  705. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  706. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  707. ccxt/tabdeal.py +364 -0
  708. ccxt/test/__init__.py +3 -0
  709. ccxt/test/base/__init__.py +29 -0
  710. ccxt/test/base/test_account.py +26 -0
  711. ccxt/test/base/test_balance.py +56 -0
  712. ccxt/test/base/test_borrow_interest.py +35 -0
  713. ccxt/test/base/test_borrow_rate.py +32 -0
  714. ccxt/test/base/test_calculate_fee.py +51 -0
  715. ccxt/test/base/test_crypto.py +127 -0
  716. ccxt/test/base/test_currency.py +76 -0
  717. ccxt/test/base/test_datetime.py +109 -0
  718. ccxt/test/base/test_decimal_to_precision.py +392 -0
  719. ccxt/test/base/test_deep_extend.py +68 -0
  720. ccxt/test/base/test_deposit_withdrawal.py +50 -0
  721. ccxt/test/base/test_exchange_datetime_functions.py +76 -0
  722. ccxt/test/base/test_funding_rate_history.py +29 -0
  723. ccxt/test/base/test_last_price.py +31 -0
  724. ccxt/test/base/test_ledger_entry.py +45 -0
  725. ccxt/test/base/test_ledger_item.py +48 -0
  726. ccxt/test/base/test_leverage_tier.py +33 -0
  727. ccxt/test/base/test_liquidation.py +50 -0
  728. ccxt/test/base/test_margin_mode.py +24 -0
  729. ccxt/test/base/test_margin_modification.py +35 -0
  730. ccxt/test/base/test_market.py +193 -0
  731. ccxt/test/base/test_number.py +411 -0
  732. ccxt/test/base/test_ohlcv.py +33 -0
  733. ccxt/test/base/test_open_interest.py +32 -0
  734. ccxt/test/base/test_order.py +64 -0
  735. ccxt/test/base/test_order_book.py +69 -0
  736. ccxt/test/base/test_position.py +60 -0
  737. ccxt/test/base/test_shared_methods.py +353 -0
  738. ccxt/test/base/test_status.py +24 -0
  739. ccxt/test/base/test_throttle.py +126 -0
  740. ccxt/test/base/test_ticker.py +92 -0
  741. ccxt/test/base/test_trade.py +47 -0
  742. ccxt/test/base/test_trading_fee.py +26 -0
  743. ccxt/test/base/test_transaction.py +39 -0
  744. ccxt/test/test_async.py +1649 -0
  745. ccxt/test/test_sync.py +1648 -0
  746. ccxt/test/tests_async.py +1558 -0
  747. ccxt/test/tests_helpers.py +287 -0
  748. ccxt/test/tests_init.py +39 -0
  749. ccxt/test/tests_sync.py +1555 -0
  750. ccxt/tetherland.py +349 -0
  751. ccxt/timex.py +1593 -0
  752. ccxt/tokocrypto.py +2405 -0
  753. ccxt/tradeogre.py +608 -0
  754. ccxt/twox.py +326 -0
  755. ccxt/ubitex.py +409 -0
  756. ccxt/upbit.py +1833 -0
  757. ccxt/vertex.py +2922 -0
  758. ccxt/wallex.py +445 -0
  759. ccxt/wavesexchange.py +2472 -0
  760. ccxt/wazirx.py +1224 -0
  761. ccxt/whitebit.py +2469 -0
  762. ccxt/woo.py +3114 -0
  763. ccxt/woofipro.py +2533 -0
  764. ccxt/xt.py +4453 -0
  765. ccxt/yobit.py +1283 -0
  766. ccxt/zaif.py +725 -0
  767. ccxt/zonda.py +1828 -0
  768. ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
  769. ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
  770. ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
  771. ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
  772. ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2066 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.blofin import ImplicitAPI
8
+ import hashlib
9
+ from ccxt.base.types import Balances, Currency, Int, Leverage, Leverages, MarginMode, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
10
+ from typing import List
11
+ from ccxt.base.errors import ExchangeError
12
+ from ccxt.base.errors import AuthenticationError
13
+ from ccxt.base.errors import ArgumentsRequired
14
+ from ccxt.base.errors import BadRequest
15
+ from ccxt.base.errors import InsufficientFunds
16
+ from ccxt.base.errors import InvalidOrder
17
+ from ccxt.base.errors import RateLimitExceeded
18
+ from ccxt.base.errors import ExchangeNotAvailable
19
+ from ccxt.base.decimal_to_precision import TICK_SIZE
20
+ from ccxt.base.precise import Precise
21
+
22
+
23
+ class blofin(Exchange, ImplicitAPI):
24
+
25
+ def describe(self):
26
+ return self.deep_extend(super(blofin, self).describe(), {
27
+ 'id': 'blofin',
28
+ 'name': 'BloFin',
29
+ 'countries': ['US'],
30
+ 'version': 'v1',
31
+ 'rateLimit': 100,
32
+ 'has': {
33
+ 'CORS': None,
34
+ 'spot': False,
35
+ 'margin': False,
36
+ 'swap': True,
37
+ 'future': False,
38
+ 'option': False,
39
+ 'addMargin': False,
40
+ 'borrowMargin': False,
41
+ 'cancelAllOrders': False,
42
+ 'cancelOrder': True,
43
+ 'cancelOrders': True,
44
+ 'closeAllPositions': False,
45
+ 'closePosition': True,
46
+ 'createDepositAddress': False,
47
+ 'createMarketBuyOrderWithCost': False,
48
+ 'createMarketSellOrderWithCost': False,
49
+ 'createOrder': True,
50
+ 'createOrders': True,
51
+ 'createOrderWithTakeProfitAndStopLoss': True,
52
+ 'createPostOnlyOrder': False,
53
+ 'createReduceOnlyOrder': False,
54
+ 'createStopLimitOrder': False,
55
+ 'createStopLossOrder': True,
56
+ 'createStopMarketOrder': False,
57
+ 'createStopOrder': False,
58
+ 'createTakeProfitOrder': True,
59
+ 'editOrder': False,
60
+ 'fetchAccounts': False,
61
+ 'fetchBalance': True,
62
+ 'fetchBidsAsks': None,
63
+ 'fetchBorrowInterest': False,
64
+ 'fetchBorrowRateHistories': False,
65
+ 'fetchBorrowRateHistory': False,
66
+ 'fetchCanceledOrders': False,
67
+ 'fetchClosedOrder': False,
68
+ 'fetchClosedOrders': False,
69
+ 'fetchCrossBorrowRate': False,
70
+ 'fetchCrossBorrowRates': False,
71
+ 'fetchCurrencies': False,
72
+ 'fetchDeposit': False,
73
+ 'fetchDepositAddress': False,
74
+ 'fetchDepositAddresses': False,
75
+ 'fetchDepositAddressesByNetwork': False,
76
+ 'fetchDeposits': True,
77
+ 'fetchDepositsWithdrawals': False,
78
+ 'fetchDepositWithdrawFee': 'emulated',
79
+ 'fetchDepositWithdrawFees': False,
80
+ 'fetchFundingHistory': True,
81
+ 'fetchFundingRate': True,
82
+ 'fetchFundingRateHistory': True,
83
+ 'fetchFundingRates': False,
84
+ 'fetchGreeks': False,
85
+ 'fetchIndexOHLCV': False,
86
+ 'fetchIsolatedBorrowRate': False,
87
+ 'fetchIsolatedBorrowRates': False,
88
+ 'fetchL3OrderBook': False,
89
+ 'fetchLedger': True,
90
+ 'fetchLedgerEntry': None,
91
+ 'fetchLeverage': True,
92
+ 'fetchLeverages': True,
93
+ 'fetchLeverageTiers': False,
94
+ 'fetchMarginMode': True,
95
+ 'fetchMarginModes': False,
96
+ 'fetchMarketLeverageTiers': False,
97
+ 'fetchMarkets': True,
98
+ 'fetchMarkOHLCV': False,
99
+ 'fetchMySettlementHistory': False,
100
+ 'fetchMyTrades': True,
101
+ 'fetchOHLCV': True,
102
+ 'fetchOpenInterest': False,
103
+ 'fetchOpenInterestHistory': False,
104
+ 'fetchOpenOrder': None,
105
+ 'fetchOpenOrders': True,
106
+ 'fetchOrder': True,
107
+ 'fetchOrderBook': True,
108
+ 'fetchOrderBooks': False,
109
+ 'fetchOrders': False,
110
+ 'fetchOrderTrades': True,
111
+ 'fetchPermissions': None,
112
+ 'fetchPosition': True,
113
+ 'fetchPositions': True,
114
+ 'fetchPositionsForSymbol': False,
115
+ 'fetchPositionsRisk': False,
116
+ 'fetchPremiumIndexOHLCV': False,
117
+ 'fetchSettlementHistory': False,
118
+ 'fetchStatus': False,
119
+ 'fetchTicker': True,
120
+ 'fetchTickers': True,
121
+ 'fetchTime': False,
122
+ 'fetchTrades': True,
123
+ 'fetchTradingFee': False,
124
+ 'fetchTradingFees': False,
125
+ 'fetchTradingLimits': False,
126
+ 'fetchTransactionFee': False,
127
+ 'fetchTransactionFees': False,
128
+ 'fetchTransactions': False,
129
+ 'fetchTransfer': False,
130
+ 'fetchTransfers': False,
131
+ 'fetchUnderlyingAssets': False,
132
+ 'fetchVolatilityHistory': False,
133
+ 'fetchWithdrawal': False,
134
+ 'fetchWithdrawals': True,
135
+ 'fetchWithdrawalWhitelist': False,
136
+ 'reduceMargin': False,
137
+ 'repayCrossMargin': False,
138
+ 'setLeverage': True,
139
+ 'setMargin': False,
140
+ 'setMarginMode': False,
141
+ 'setPositionMode': False,
142
+ 'signIn': False,
143
+ 'transfer': True,
144
+ 'withdraw': False,
145
+ },
146
+ 'timeframes': {
147
+ '1m': '1m',
148
+ '3m': '3m',
149
+ '5m': '5m',
150
+ '15m': '15m',
151
+ '30m': '30m',
152
+ '1h': '1H',
153
+ '2h': '2H',
154
+ '4h': '4H',
155
+ '6h': '6H',
156
+ '12h': '12H',
157
+ '1d': '1D',
158
+ '1w': '1W',
159
+ '1M': '1M',
160
+ '3M': '3M',
161
+ },
162
+ 'hostname': 'www.blofin.com',
163
+ 'urls': {
164
+ 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/255a7b29-341f-4d20-8342-fbfae4932807',
165
+ 'api': {
166
+ 'rest': 'https://openapi.blofin.com',
167
+ },
168
+ 'referral': {
169
+ 'url': 'https://blofin.com/register?referral_code=jBd8U1',
170
+ 'discount': 0.05,
171
+ },
172
+ 'www': 'https://www.blofin.com',
173
+ 'doc': 'https://blofin.com/docs',
174
+ },
175
+ 'api': {
176
+ 'public': {
177
+ 'get': {
178
+ 'market/instruments': 1,
179
+ 'market/tickers': 1,
180
+ 'market/books': 1,
181
+ 'market/trades': 1,
182
+ 'market/candles': 1,
183
+ 'market/mark-price': 1,
184
+ 'market/funding-rate': 1,
185
+ 'market/funding-rate-history': 1,
186
+ },
187
+ },
188
+ 'private': {
189
+ 'get': {
190
+ 'asset/balances': 1,
191
+ 'trade/orders-pending': 1,
192
+ 'trade/fills-history': 1,
193
+ 'asset/deposit-history': 1,
194
+ 'asset/withdrawal-history': 1,
195
+ 'asset/bills': 1,
196
+ 'account/balance': 1,
197
+ 'account/positions': 1,
198
+ 'account/leverage-info': 1,
199
+ 'account/margin-mode': 1,
200
+ 'account/batch-leverage-info': 1,
201
+ 'trade/orders-tpsl-pending': 1,
202
+ 'trade/orders-history': 1,
203
+ 'trade/orders-tpsl-history': 1,
204
+ 'user/query-apikey': 1,
205
+ 'affiliate/basic': 1,
206
+ },
207
+ 'post': {
208
+ 'trade/order': 1,
209
+ 'trade/cancel-order': 1,
210
+ 'account/set-leverage': 1,
211
+ 'trade/batch-orders': 1,
212
+ 'trade/order-tpsl': 1,
213
+ 'trade/cancel-batch-orders': 1,
214
+ 'trade/cancel-tpsl': 1,
215
+ 'trade/close-position': 1,
216
+ 'asset/transfer': 1,
217
+ },
218
+ },
219
+ },
220
+ 'fees': {
221
+ 'swap': {
222
+ 'taker': self.parse_number('0.00060'),
223
+ 'maker': self.parse_number('0.00020'),
224
+ },
225
+ },
226
+ 'requiredCredentials': {
227
+ 'apiKey': True,
228
+ 'secret': True,
229
+ 'password': True,
230
+ },
231
+ 'exceptions': {
232
+ 'exact': {
233
+ '400': BadRequest, # Body can not be empty
234
+ '401': AuthenticationError, # Invalid signature
235
+ '500': ExchangeError, # Internal Server Error
236
+ '404': BadRequest, # not found
237
+ '405': BadRequest, # Method Not Allowed
238
+ '406': BadRequest, # Not Acceptable
239
+ '429': RateLimitExceeded, # Too Many Requests
240
+ '152001': BadRequest, # Parameter {} cannot be empty
241
+ '152002': BadRequest, # Parameter {} error
242
+ '152003': BadRequest, # Either parameter {} or {} is required
243
+ '152004': BadRequest, # JSON syntax error
244
+ '152005': BadRequest, # Parameter error: wrong or empty
245
+ '152006': InvalidOrder, # Batch orders can be placed for up to 20 at once
246
+ '152007': InvalidOrder, # Batch orders can only be placed with the same instId and marginMode
247
+ '152008': InvalidOrder, # Only the same field is allowed for bulk cancellation of orders, orderId is preferred
248
+ '152009': InvalidOrder, # {} must be a combination of numbers, letters, or underscores, and the maximum length of characters is 32
249
+ '150003': InvalidOrder, # clientId already exist
250
+ '150004': InvalidOrder, # Insufficient balance. please adjust the amount and try again
251
+ '542': InvalidOrder, # Exceeded the maximum order size limit
252
+ '102002': InvalidOrder, # Duplicate customized order ID
253
+ '102005': InvalidOrder, # Position had been closed
254
+ '102014': InvalidOrder, # Limit order exceeds maximum order size limit
255
+ '102015': InvalidOrder, # Market order exceeds maximum order size limit
256
+ '102022': InvalidOrder, # Failed to place order. You don’t have any positions of self contract. Turn off Reduce-only to continue.
257
+ '102037': InvalidOrder, # TP trigger price should be higher than the latest trading price
258
+ '102038': InvalidOrder, # SL trigger price should be lower than the latest trading price
259
+ '102039': InvalidOrder, # TP trigger price should be lower than the latest trading price
260
+ '102040': InvalidOrder, # SL trigger price should be higher than the latest trading price
261
+ '102047': InvalidOrder, # Stop loss trigger price should be higher than the order price
262
+ '102048': InvalidOrder, # stop loss trigger price must be higher than the best bid price
263
+ '102049': InvalidOrder, # Take profit trigger price should be lower than the order price
264
+ '102050': InvalidOrder, # stop loss trigger price must be lower than the best ask price
265
+ '102051': InvalidOrder, # stop loss trigger price should be lower than the order price
266
+ '102052': InvalidOrder, # take profit trigger price should be higher than the order price
267
+ '102053': InvalidOrder, # take profit trigger price should be lower than the best bid price
268
+ '102054': InvalidOrder, # take profit trigger price should be higher than the best ask price
269
+ '102055': InvalidOrder, # stop loss trigger price should be lower than the best ask price
270
+ '102064': BadRequest, # Buy price is not within the price limit(Minimum: 310.40; Maximum:1,629.40)
271
+ '102065': BadRequest, # Sell price is not within the price limit
272
+ '102068': BadRequest, # Cancel failed order has been filled, triggered, canceled or does not exist
273
+ '103013': ExchangeError, # Internal error; unable to process your request. Please try again.
274
+ 'Order failed. Insufficient USDT margin in account': InsufficientFunds, # Insufficient USDT margin in account
275
+ },
276
+ 'broad': {
277
+ 'Internal Server Error': ExchangeNotAvailable, # {"code":500,"data":{},"detailMsg":"","error_code":"500","error_message":"Internal Server Error","msg":"Internal Server Error"}
278
+ 'server error': ExchangeNotAvailable, # {"code":500,"data":{},"detailMsg":"","error_code":"500","error_message":"server error 1236805249","msg":"server error 1236805249"}
279
+ },
280
+ },
281
+ 'httpExceptions': {
282
+ '429': ExchangeNotAvailable, # https://github.com/ccxt/ccxt/issues/9612
283
+ },
284
+ 'precisionMode': TICK_SIZE,
285
+ 'options': {
286
+ 'brokerId': 'ec6dd3a7dd982d0b',
287
+ 'accountsByType': {
288
+ 'swap': 'futures',
289
+ 'future': 'futures',
290
+ },
291
+ 'accountsById': {
292
+ 'futures': 'swap',
293
+ },
294
+ 'sandboxMode': False,
295
+ 'defaultNetwork': 'ERC20',
296
+ 'defaultNetworks': {
297
+ 'ETH': 'ERC20',
298
+ 'BTC': 'BTC',
299
+ 'USDT': 'TRC20',
300
+ },
301
+ 'networks': {
302
+ 'BTC': 'Bitcoin',
303
+ 'BEP20': 'BSC',
304
+ 'ERC20': 'ERC20',
305
+ 'TRC20': 'TRC20',
306
+ },
307
+ 'fetchOpenInterestHistory': {
308
+ 'timeframes': {
309
+ '5m': '5m',
310
+ '1h': '1H',
311
+ '8h': '8H',
312
+ '1d': '1D',
313
+ '5M': '5m',
314
+ '1H': '1H',
315
+ '8H': '8H',
316
+ '1D': '1D',
317
+ },
318
+ },
319
+ 'fetchOHLCV': {
320
+ # 'type': 'Candles', # Candles or HistoryCandles, IndexCandles, MarkPriceCandles
321
+ 'timezone': 'UTC', # UTC, HK
322
+ },
323
+ 'fetchPositions': {
324
+ 'method': 'privateGetAccountPositions', # privateGetAccountPositions or privateGetAccountPositionsHistory
325
+ },
326
+ 'createOrder': 'privatePostTradeOrder', # or 'privatePostTradeOrderTpsl'
327
+ 'createMarketBuyOrderRequiresPrice': False,
328
+ 'fetchMarkets': ['swap'],
329
+ 'defaultType': 'swap',
330
+ 'fetchLedger': {
331
+ 'method': 'privateGetAssetBills',
332
+ },
333
+ 'fetchOpenOrders': {
334
+ 'method': 'privateGetTradeOrdersPending',
335
+ },
336
+ 'cancelOrders': {
337
+ 'method': 'privatePostTradeCancelBatchOrders',
338
+ },
339
+ 'fetchCanceledOrders': {
340
+ 'method': 'privateGetTradeOrdersHistory', # privateGetTradeOrdersTpslHistory
341
+ },
342
+ 'fetchClosedOrders': {
343
+ 'method': 'privateGetTradeOrdersHistory', # privateGetTradeOrdersTpslHistory
344
+ },
345
+ 'withdraw': {
346
+ # a funding password credential is required by the exchange for the
347
+ # withdraw call(not to be confused with the api password credential)
348
+ 'password': None,
349
+ 'pwd': None, # password or pwd both work
350
+ },
351
+ 'exchangeType': {
352
+ 'spot': 'SPOT',
353
+ 'swap': 'SWAP',
354
+ 'SPOT': 'SPOT',
355
+ 'SWAP': 'SWAP',
356
+ },
357
+ },
358
+ })
359
+
360
+ async def fetch_markets(self, params={}) -> List[Market]:
361
+ """
362
+ retrieves data on all markets for blofin
363
+ :see: https://blofin.com/docs#get-instruments
364
+ :param dict [params]: extra parameters specific to the exchange API endpoint
365
+ :returns dict[]: an array of objects representing market data
366
+ """
367
+ response = await self.publicGetMarketInstruments(params)
368
+ data = self.safe_list(response, 'data', [])
369
+ return self.parse_markets(data)
370
+
371
+ def parse_market(self, market: dict) -> Market:
372
+ id = self.safe_string(market, 'instId')
373
+ type = self.safe_string_lower(market, 'instType')
374
+ spot = (type == 'spot')
375
+ future = (type == 'future')
376
+ swap = (type == 'swap')
377
+ option = (type == 'option')
378
+ contract = swap or future
379
+ baseId = self.safe_string(market, 'baseCurrency')
380
+ quoteId = self.safe_string(market, 'quoteCurrency')
381
+ settleId = self.safe_string(market, 'quoteCurrency')
382
+ settle = self.safe_currency_code(settleId)
383
+ base = self.safe_currency_code(baseId)
384
+ quote = self.safe_currency_code(quoteId)
385
+ symbol = base + '/' + quote
386
+ if swap:
387
+ symbol = symbol + ':' + settle
388
+ expiry = None
389
+ strikePrice = None
390
+ optionType = None
391
+ tickSize = self.safe_string(market, 'tickSize')
392
+ fees = self.safe_dict_2(self.fees, type, 'trading', {})
393
+ taker = self.safe_number(fees, 'taker')
394
+ maker = self.safe_number(fees, 'maker')
395
+ maxLeverage = self.safe_string(market, 'maxLeverage', '100')
396
+ maxLeverage = Precise.string_max(maxLeverage, '1')
397
+ isActive = (self.safe_string(market, 'state') == 'live')
398
+ return self.safe_market_structure({
399
+ 'id': id,
400
+ 'symbol': symbol,
401
+ 'base': base,
402
+ 'quote': quote,
403
+ 'baseId': baseId,
404
+ 'quoteId': quoteId,
405
+ 'settle': settle,
406
+ 'settleId': settleId,
407
+ 'type': type,
408
+ 'spot': spot,
409
+ 'option': option,
410
+ 'margin': spot and (Precise.string_gt(maxLeverage, '1')),
411
+ 'swap': swap,
412
+ 'future': future,
413
+ 'active': isActive,
414
+ 'taker': taker,
415
+ 'maker': maker,
416
+ 'contract': contract,
417
+ 'linear': (quoteId == settleId) if contract else None,
418
+ 'inverse': (baseId == settleId) if contract else None,
419
+ 'contractSize': self.safe_number(market, 'contractValue') if contract else None,
420
+ 'expiry': expiry,
421
+ 'expiryDatetime': expiry,
422
+ 'strike': strikePrice,
423
+ 'optionType': optionType,
424
+ 'created': self.safe_integer(market, 'listTime'),
425
+ 'precision': {
426
+ 'amount': self.safe_number(market, 'lotSize'),
427
+ 'price': self.parse_number(tickSize),
428
+ },
429
+ 'limits': {
430
+ 'leverage': {
431
+ 'min': self.parse_number('1'),
432
+ 'max': self.parse_number(maxLeverage),
433
+ },
434
+ 'amount': {
435
+ 'min': self.safe_number(market, 'minSize'),
436
+ 'max': None,
437
+ },
438
+ 'price': {
439
+ 'min': None,
440
+ 'max': None,
441
+ },
442
+ 'cost': {
443
+ 'min': None,
444
+ 'max': None,
445
+ },
446
+ },
447
+ 'info': market,
448
+ })
449
+
450
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
451
+ """
452
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
453
+ :see: https://blofin.com/docs#get-order-book
454
+ :param str symbol: unified symbol of the market to fetch the order book for
455
+ :param int [limit]: the maximum amount of order book entries to return
456
+ :param dict [params]: extra parameters specific to the exchange API endpoint
457
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
458
+ """
459
+ await self.load_markets()
460
+ market = self.market(symbol)
461
+ request: dict = {
462
+ 'instId': market['id'],
463
+ }
464
+ limit = 50 if (limit is None) else limit
465
+ if limit is not None:
466
+ request['size'] = limit # max 100
467
+ response = await self.publicGetMarketBooks(self.extend(request, params))
468
+ #
469
+ # {
470
+ # "code": "0",
471
+ # "msg": "",
472
+ # "data": [
473
+ # {
474
+ # "asks": [
475
+ # ["0.07228","4.211619","0","2"], # price, amount, liquidated orders, total open orders
476
+ # ["0.0723","299.880364","0","2"],
477
+ # ["0.07231","3.72832","0","1"],
478
+ # ],
479
+ # "bids": [
480
+ # ["0.07221","18.5","0","1"],
481
+ # ["0.0722","18.5","0","1"],
482
+ # ["0.07219","0.505407","0","1"],
483
+ # ],
484
+ # "ts": "1621438475342"
485
+ # }
486
+ # ]
487
+ # }
488
+ #
489
+ data = self.safe_list(response, 'data', [])
490
+ first = self.safe_dict(data, 0, {})
491
+ timestamp = self.safe_integer(first, 'ts')
492
+ return self.parse_order_book(first, symbol, timestamp)
493
+
494
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
495
+ timestamp = self.safe_integer(ticker, 'ts')
496
+ marketId = self.safe_string(ticker, 'instId')
497
+ market = self.safe_market(marketId, market, '-')
498
+ symbol = market['symbol']
499
+ last = self.safe_string(ticker, 'last')
500
+ open = self.safe_string(ticker, 'open24h')
501
+ spot = self.safe_bool(market, 'spot', False)
502
+ quoteVolume = self.safe_string(ticker, 'volCurrency24h') if spot else None
503
+ baseVolume = self.safe_string(ticker, 'vol24h')
504
+ high = self.safe_string(ticker, 'high24h')
505
+ low = self.safe_string(ticker, 'low24h')
506
+ return self.safe_ticker({
507
+ 'symbol': symbol,
508
+ 'timestamp': timestamp,
509
+ 'datetime': self.iso8601(timestamp),
510
+ 'high': high,
511
+ 'low': low,
512
+ 'bid': self.safe_string(ticker, 'bidPrice'),
513
+ 'bidVolume': self.safe_string(ticker, 'bidSize'),
514
+ 'ask': self.safe_string(ticker, 'askPrice'),
515
+ 'askVolume': self.safe_string(ticker, 'askSize'),
516
+ 'vwap': None,
517
+ 'open': open,
518
+ 'close': last,
519
+ 'last': last,
520
+ 'previousClose': None,
521
+ 'change': None,
522
+ 'percentage': None,
523
+ 'average': None,
524
+ 'baseVolume': baseVolume,
525
+ 'quoteVolume': quoteVolume,
526
+ 'info': ticker,
527
+ }, market)
528
+
529
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
530
+ """
531
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
532
+ :see: https://blofin.com/docs#get-tickers
533
+ :param str symbol: unified symbol of the market to fetch the ticker for
534
+ :param dict [params]: extra parameters specific to the exchange API endpoint
535
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
536
+ """
537
+ await self.load_markets()
538
+ market = self.market(symbol)
539
+ request: dict = {
540
+ 'instId': market['id'],
541
+ }
542
+ response = await self.publicGetMarketTickers(self.extend(request, params))
543
+ data = self.safe_list(response, 'data', [])
544
+ first = self.safe_dict(data, 0, {})
545
+ return self.parse_ticker(first, market)
546
+
547
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
548
+ """
549
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
550
+ :see: https://blofin.com/docs#get-tickers
551
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
552
+ :param dict [params]: extra parameters specific to the exchange API endpoint
553
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
554
+ """
555
+ await self.load_markets()
556
+ symbols = self.market_symbols(symbols)
557
+ response = await self.publicGetMarketTickers(params)
558
+ tickers = self.safe_list(response, 'data', [])
559
+ return self.parse_tickers(tickers, symbols)
560
+
561
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
562
+ #
563
+ # fetch trades
564
+ # {
565
+ # "tradeId": "3263934920",
566
+ # "instId": "LTC-USDT",
567
+ # "price": "67.87",
568
+ # "size": "1",
569
+ # "side": "buy",
570
+ # "ts": "1707232020854"
571
+ # }
572
+ # my trades
573
+ # {
574
+ # "instId": "LTC-USDT",
575
+ # "tradeId": "1440847",
576
+ # "orderId": "2075705202",
577
+ # "fillPrice": "67.850000000000000000",
578
+ # "fillSize": "1.000000000000000000",
579
+ # "fillPnl": "0.000000000000000000",
580
+ # "side": "buy",
581
+ # "positionSide": "net",
582
+ # "fee": "0.040710000000000000",
583
+ # "ts": "1707224678878",
584
+ # "brokerId": ""
585
+ # }
586
+ #
587
+ id = self.safe_string(trade, 'tradeId')
588
+ marketId = self.safe_string(trade, 'instId')
589
+ market = self.safe_market(marketId, market, '-')
590
+ symbol = market['symbol']
591
+ timestamp = self.safe_integer(trade, 'ts')
592
+ price = self.safe_string_2(trade, 'price', 'fillPrice')
593
+ amount = self.safe_string_2(trade, 'size', 'fillSize')
594
+ side = self.safe_string(trade, 'side')
595
+ orderId = self.safe_string(trade, 'orderId')
596
+ feeCost = self.safe_string(trade, 'fee')
597
+ fee = None
598
+ if feeCost is not None:
599
+ fee = {
600
+ 'cost': feeCost,
601
+ 'currency': market['settle'],
602
+ }
603
+ return self.safe_trade({
604
+ 'info': trade,
605
+ 'timestamp': timestamp,
606
+ 'datetime': self.iso8601(timestamp),
607
+ 'symbol': symbol,
608
+ 'id': id,
609
+ 'order': orderId,
610
+ 'type': None,
611
+ 'takerOrMaker': None,
612
+ 'side': side,
613
+ 'price': price,
614
+ 'amount': amount,
615
+ 'cost': None,
616
+ 'fee': fee,
617
+ }, market)
618
+
619
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
620
+ """
621
+ get the list of most recent trades for a particular symbol
622
+ :see: https://blofin.com/docs#get-trades
623
+ :param str symbol: unified symbol of the market to fetch trades for
624
+ :param int [since]: timestamp in ms of the earliest trade to fetch
625
+ :param int [limit]: the maximum amount of trades to fetch
626
+ :param dict [params]: extra parameters specific to the exchange API endpoint
627
+ :param boolean [params.paginate]: *only applies to publicGetMarketHistoryTrades* default False, when True will automatically paginate by calling self endpoint multiple times
628
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
629
+ """
630
+ await self.load_markets()
631
+ paginate = False
632
+ paginate, params = self.handle_option_and_params(params, 'fetchTrades', 'paginate')
633
+ if paginate:
634
+ return await self.fetch_paginated_call_cursor('fetchTrades', symbol, since, limit, params, 'tradeId', 'after', None, 100)
635
+ market = self.market(symbol)
636
+ request: dict = {
637
+ 'instId': market['id'],
638
+ }
639
+ response = None
640
+ if limit is not None:
641
+ request['limit'] = limit # default 100
642
+ method = None
643
+ method, params = self.handle_option_and_params(params, 'fetchTrades', 'method', 'publicGetMarketTrades')
644
+ if method == 'publicGetMarketTrades':
645
+ response = await self.publicGetMarketTrades(self.extend(request, params))
646
+ data = self.safe_list(response, 'data', [])
647
+ return self.parse_trades(data, market, since, limit)
648
+
649
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
650
+ #
651
+ # [
652
+ # "1678928760000", # timestamp
653
+ # "24341.4", # open
654
+ # "24344", # high
655
+ # "24313.2", # low
656
+ # "24323", # close
657
+ # "628", # contract volume
658
+ # "2.5819", # base volume
659
+ # "62800", # quote volume
660
+ # "0" # candlestick state
661
+ # ]
662
+ #
663
+ return [
664
+ self.safe_integer(ohlcv, 0),
665
+ self.safe_number(ohlcv, 1),
666
+ self.safe_number(ohlcv, 2),
667
+ self.safe_number(ohlcv, 3),
668
+ self.safe_number(ohlcv, 4),
669
+ self.safe_number(ohlcv, 6),
670
+ ]
671
+
672
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
673
+ """
674
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
675
+ :see: https://blofin.com/docs#get-candlesticks
676
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
677
+ :param str timeframe: the length of time each candle represents
678
+ :param int [since]: timestamp in ms of the earliest candle to fetch
679
+ :param int [limit]: the maximum amount of candles to fetch
680
+ :param dict [params]: extra parameters specific to the exchange API endpoint
681
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
682
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
683
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
684
+ """
685
+ await self.load_markets()
686
+ market = self.market(symbol)
687
+ paginate = False
688
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
689
+ if paginate:
690
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 100)
691
+ if limit is None:
692
+ limit = 100 # default 100, max 100
693
+ request: dict = {
694
+ 'instId': market['id'],
695
+ 'bar': self.safe_string(self.timeframes, timeframe, timeframe),
696
+ 'limit': limit,
697
+ }
698
+ until = self.safe_integer(params, 'until')
699
+ if until is not None:
700
+ request['after'] = until
701
+ params = self.omit(params, 'until')
702
+ response = None
703
+ response = await self.publicGetMarketCandles(self.extend(request, params))
704
+ data = self.safe_list(response, 'data', [])
705
+ return self.parse_ohlcvs(data, market, timeframe, since, limit)
706
+
707
+ async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
708
+ """
709
+ fetches historical funding rate prices
710
+ :see: https://blofin.com/docs#get-funding-rate-history
711
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
712
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
713
+ :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
714
+ :param dict [params]: extra parameters specific to the exchange API endpoint
715
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
716
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
717
+ """
718
+ if symbol is None:
719
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
720
+ await self.load_markets()
721
+ paginate = False
722
+ paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
723
+ if paginate:
724
+ return await self.fetch_paginated_call_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params)
725
+ market = self.market(symbol)
726
+ request: dict = {
727
+ 'instId': market['id'],
728
+ }
729
+ if since is not None:
730
+ request['before'] = max(since - 1, 0)
731
+ if limit is not None:
732
+ request['limit'] = limit
733
+ response = await self.publicGetMarketFundingRateHistory(self.extend(request, params))
734
+ rates = []
735
+ data = self.safe_list(response, 'data', [])
736
+ for i in range(0, len(data)):
737
+ rate = data[i]
738
+ timestamp = self.safe_integer(rate, 'fundingTime')
739
+ rates.append({
740
+ 'info': rate,
741
+ 'symbol': market['symbol'],
742
+ 'fundingRate': self.safe_number(rate, 'fundingRate'),
743
+ 'timestamp': timestamp,
744
+ 'datetime': self.iso8601(timestamp),
745
+ })
746
+ sorted = self.sort_by(rates, 'timestamp')
747
+ return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
748
+
749
+ def parse_funding_rate(self, contract, market: Market = None):
750
+ #
751
+ # {
752
+ # "fundingRate": "0.00027815",
753
+ # "fundingTime": "1634256000000",
754
+ # "instId": "BTC-USD-SWAP",
755
+ # "instType": "SWAP",
756
+ # "nextFundingRate": "0.00017",
757
+ # "nextFundingTime": "1634284800000"
758
+ # }
759
+ #
760
+ # in the response above nextFundingRate is actually two funding rates from now
761
+ #
762
+ nextFundingRateTimestamp = self.safe_integer(contract, 'nextFundingTime')
763
+ marketId = self.safe_string(contract, 'instId')
764
+ symbol = self.safe_symbol(marketId, market)
765
+ nextFundingRate = self.safe_number(contract, 'nextFundingRate')
766
+ fundingTime = self.safe_integer(contract, 'fundingTime')
767
+ # > The current interest is 0.
768
+ return {
769
+ 'info': contract,
770
+ 'symbol': symbol,
771
+ 'markPrice': None,
772
+ 'indexPrice': None,
773
+ 'interestRate': self.parse_number('0'),
774
+ 'estimatedSettlePrice': None,
775
+ 'timestamp': None,
776
+ 'datetime': None,
777
+ 'fundingRate': self.safe_number(contract, 'fundingRate'),
778
+ 'fundingTimestamp': fundingTime,
779
+ 'fundingDatetime': self.iso8601(fundingTime),
780
+ 'nextFundingRate': nextFundingRate,
781
+ 'nextFundingTimestamp': nextFundingRateTimestamp,
782
+ 'nextFundingDatetime': self.iso8601(nextFundingRateTimestamp),
783
+ 'previousFundingRate': None,
784
+ 'previousFundingTimestamp': None,
785
+ 'previousFundingDatetime': None,
786
+ }
787
+
788
+ async def fetch_funding_rate(self, symbol: str, params={}):
789
+ """
790
+ fetch the current funding rate
791
+ :see: https://blofin.com/docs#get-funding-rate
792
+ :param str symbol: unified market symbol
793
+ :param dict [params]: extra parameters specific to the exchange API endpoint
794
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
795
+ """
796
+ await self.load_markets()
797
+ market = self.market(symbol)
798
+ if not market['swap']:
799
+ raise ExchangeError(self.id + ' fetchFundingRate() is only valid for swap markets')
800
+ request: dict = {
801
+ 'instId': market['id'],
802
+ }
803
+ response = await self.publicGetMarketFundingRate(self.extend(request, params))
804
+ #
805
+ # {
806
+ # "code": "0",
807
+ # "data": [
808
+ # {
809
+ # "fundingRate": "0.00027815",
810
+ # "fundingTime": "1634256000000",
811
+ # "instId": "BTC-USD-SWAP",
812
+ # "instType": "SWAP",
813
+ # "nextFundingRate": "0.00017",
814
+ # "nextFundingTime": "1634284800000"
815
+ # }
816
+ # ],
817
+ # "msg": ""
818
+ # }
819
+ #
820
+ data = self.safe_list(response, 'data', [])
821
+ entry = self.safe_dict(data, 0, {})
822
+ return self.parse_funding_rate(entry, market)
823
+
824
+ def parse_balance_by_type(self, type, response):
825
+ if type:
826
+ return self.parse_funding_balance(response)
827
+ else:
828
+ return self.parse_trading_balance(response)
829
+
830
+ def parse_trading_balance(self, response):
831
+ #
832
+ # {
833
+ # "code": "0",
834
+ # "msg": "success",
835
+ # "data": {
836
+ # "ts": "1697021343571",
837
+ # "totalEquity": "10011254.077985990315787910",
838
+ # "isolatedEquity": "861.763132108800000000",
839
+ # "details": [
840
+ # {
841
+ # "currency": "USDT",
842
+ # "equity": "10014042.988958415234430699548",
843
+ # "balance": "10013119.885958415234430699",
844
+ # "ts": "1697021343571",
845
+ # "isolatedEquity": "862.003200000000000000048",
846
+ # "available": "9996399.4708691159703362725",
847
+ # "availableEquity": "9996399.4708691159703362725",
848
+ # "frozen": "15805.149672632597427761",
849
+ # "orderFrozen": "14920.994472632597427761",
850
+ # "equityUsd": "10011254.077985990315787910",
851
+ # "isolatedUnrealizedPnl": "-22.151999999999999999952",
852
+ # "bonus": "0"
853
+ # }
854
+ # ]
855
+ # }
856
+ # }
857
+ #
858
+ result: dict = {'info': response}
859
+ data = self.safe_dict(response, 'data', {})
860
+ timestamp = self.safe_integer(data, 'ts')
861
+ details = self.safe_list(data, 'details', [])
862
+ for i in range(0, len(details)):
863
+ balance = details[i]
864
+ currencyId = self.safe_string(balance, 'currency')
865
+ code = self.safe_currency_code(currencyId)
866
+ account = self.account()
867
+ # it may be incorrect to use total, free and used for swap accounts
868
+ eq = self.safe_string(balance, 'equity')
869
+ availEq = self.safe_string(balance, 'available')
870
+ if (eq is None) or (availEq is None):
871
+ account['free'] = self.safe_string(balance, 'availableEquity')
872
+ account['used'] = self.safe_string(balance, 'frozen')
873
+ else:
874
+ account['total'] = eq
875
+ account['free'] = availEq
876
+ result[code] = account
877
+ result['timestamp'] = timestamp
878
+ result['datetime'] = self.iso8601(timestamp)
879
+ return self.safe_balance(result)
880
+
881
+ def parse_funding_balance(self, response):
882
+ #
883
+ # {
884
+ # "code": "0",
885
+ # "msg": "success",
886
+ # "data": [
887
+ # {
888
+ # "currency": "USDT",
889
+ # "balance": "10012514.919418081548717298",
890
+ # "available": "9872132.414278782284622898",
891
+ # "frozen": "138556.471805965930761067",
892
+ # "bonus": "0"
893
+ # }
894
+ # ]
895
+ # }
896
+ #
897
+ result: dict = {'info': response}
898
+ data = self.safe_list(response, 'data', [])
899
+ for i in range(0, len(data)):
900
+ balance = data[i]
901
+ currencyId = self.safe_string(balance, 'currency')
902
+ code = self.safe_currency_code(currencyId)
903
+ account = self.account()
904
+ # it may be incorrect to use total, free and used for swap accounts
905
+ account['total'] = self.safe_string(balance, 'balance')
906
+ account['free'] = self.safe_string(balance, 'available')
907
+ account['used'] = self.safe_string(balance, 'frozen')
908
+ result[code] = account
909
+ return self.safe_balance(result)
910
+
911
+ def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
912
+ return {
913
+ 'info': fee,
914
+ 'symbol': self.safe_symbol(None, market),
915
+ # blofin returns the fees values opposed to other exchanges, so the sign needs to be flipped
916
+ 'maker': self.parse_number(Precise.string_neg(self.safe_string_2(fee, 'maker', 'makerU'))),
917
+ 'taker': self.parse_number(Precise.string_neg(self.safe_string_2(fee, 'taker', 'takerU'))),
918
+ 'percentage': None,
919
+ 'tierBased': None,
920
+ }
921
+
922
+ async def fetch_balance(self, params={}) -> Balances:
923
+ """
924
+ query for balance and get the amount of funds available for trading or funds locked in orders
925
+ :see: https://blofin.com/docs#get-balance
926
+ :see: https://blofin.com/docs#get-futures-account-balance
927
+ :param dict [params]: extra parameters specific to the exchange API endpoint
928
+ :param str [params.accountType]: the type of account to fetch the balance for, either 'funding' or 'futures' or 'copy_trading' or 'earn'
929
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
930
+ """
931
+ await self.load_markets()
932
+ accountType = self.safe_string_2(params, 'accountType', 'type')
933
+ params = self.omit(params, ['accountType', 'type'])
934
+ request: dict = {
935
+ }
936
+ response = None
937
+ if accountType is not None:
938
+ options = self.safe_dict(self.options, 'accountsByType', {})
939
+ parsedAccountType = self.safe_string(options, accountType, accountType)
940
+ request['accountType'] = parsedAccountType
941
+ response = await self.privateGetAssetBalances(self.extend(request, params))
942
+ else:
943
+ response = await self.privateGetAccountBalance(self.extend(request, params))
944
+ return self.parse_balance_by_type(accountType, response)
945
+
946
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
947
+ market = self.market(symbol)
948
+ request: dict = {
949
+ 'instId': market['id'],
950
+ 'side': side,
951
+ 'orderType': type,
952
+ 'size': self.amount_to_precision(symbol, amount),
953
+ 'brokerId': self.safe_string(self.options, 'brokerId', 'ec6dd3a7dd982d0b'),
954
+ }
955
+ marginMode = None
956
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params, 'cross')
957
+ request['marginMode'] = marginMode
958
+ timeInForce = self.safe_string(params, 'timeInForce', 'GTC')
959
+ isMarketOrder = type == 'market'
960
+ params = self.omit(params, ['timeInForce'])
961
+ ioc = (timeInForce == 'IOC') or (type == 'ioc')
962
+ marketIOC = (isMarketOrder and ioc)
963
+ if isMarketOrder or marketIOC:
964
+ request['orderType'] = 'market'
965
+ else:
966
+ request['price'] = self.price_to_precision(symbol, price)
967
+ postOnly = False
968
+ postOnly, params = self.handle_post_only(isMarketOrder, type == 'post_only', params)
969
+ if postOnly:
970
+ request['type'] = 'post_only'
971
+ stopLoss = self.safe_dict(params, 'stopLoss')
972
+ takeProfit = self.safe_dict(params, 'takeProfit')
973
+ params = self.omit(params, ['stopLoss', 'takeProfit'])
974
+ isStopLoss = stopLoss is not None
975
+ isTakeProfit = takeProfit is not None
976
+ if isStopLoss or isTakeProfit:
977
+ if isStopLoss:
978
+ slTriggerPrice = self.safe_string_2(stopLoss, 'triggerPrice', 'stopPrice')
979
+ request['slTriggerPrice'] = self.price_to_precision(symbol, slTriggerPrice)
980
+ slOrderPrice = self.safe_string(stopLoss, 'price', '-1')
981
+ request['slOrderPrice'] = self.price_to_precision(symbol, slOrderPrice)
982
+ if isTakeProfit:
983
+ tpTriggerPrice = self.safe_string_2(takeProfit, 'triggerPrice', 'stopPrice')
984
+ request['tpTriggerPrice'] = self.price_to_precision(symbol, tpTriggerPrice)
985
+ tpPrice = self.safe_string(takeProfit, 'price', '-1')
986
+ request['tpOrderPrice'] = self.price_to_precision(symbol, tpPrice)
987
+ return self.extend(request, params)
988
+
989
+ def parse_order_status(self, status: Str):
990
+ statuses: dict = {
991
+ 'canceled': 'canceled',
992
+ 'order_failed': 'canceled',
993
+ 'live': 'open',
994
+ 'partially_filled': 'open',
995
+ 'filled': 'closed',
996
+ 'effective': 'closed',
997
+ }
998
+ return self.safe_string(statuses, status, status)
999
+
1000
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1001
+ #
1002
+ # {
1003
+ # "orderId": "2075628533",
1004
+ # "clientOrderId": "",
1005
+ # "instId": "LTC-USDT",
1006
+ # "marginMode": "cross",
1007
+ # "positionSide": "net",
1008
+ # "side": "buy",
1009
+ # "orderType": "market",
1010
+ # "price": "0.000000000000000000",
1011
+ # "size": "1.000000000000000000",
1012
+ # "reduceOnly": "true",
1013
+ # "leverage": "3",
1014
+ # "state": "filled",
1015
+ # "filledSize": "1.000000000000000000",
1016
+ # "pnl": "-0.050000000000000000",
1017
+ # "averagePrice": "68.110000000000000000",
1018
+ # "fee": "0.040866000000000000",
1019
+ # "createTime": "1706891359010",
1020
+ # "updateTime": "1706891359098",
1021
+ # "orderCategory": "normal",
1022
+ # "tpTriggerPrice": null,
1023
+ # "tpOrderPrice": null,
1024
+ # "slTriggerPrice": null,
1025
+ # "slOrderPrice": null,
1026
+ # "cancelSource": "not_canceled",
1027
+ # "cancelSourceReason": null,
1028
+ # "brokerId": "ec6dd3a7dd982d0b"
1029
+ # }
1030
+ #
1031
+ id = self.safe_string_2(order, 'tpslId', 'orderId')
1032
+ timestamp = self.safe_integer(order, 'createTime')
1033
+ lastUpdateTimestamp = self.safe_integer(order, 'updateTime')
1034
+ lastTradeTimestamp = self.safe_integer(order, 'fillTime')
1035
+ side = self.safe_string(order, 'side')
1036
+ type = self.safe_string(order, 'orderType')
1037
+ postOnly = None
1038
+ timeInForce = None
1039
+ if type == 'post_only':
1040
+ postOnly = True
1041
+ type = 'limit'
1042
+ elif type == 'fok':
1043
+ timeInForce = 'FOK'
1044
+ type = 'limit'
1045
+ elif type == 'ioc':
1046
+ timeInForce = 'IOC'
1047
+ type = 'limit'
1048
+ marketId = self.safe_string(order, 'instId')
1049
+ market = self.safe_market(marketId, market)
1050
+ symbol = self.safe_symbol(marketId, market, '-')
1051
+ filled = self.safe_string(order, 'filledSize')
1052
+ price = self.safe_string_2(order, 'px', 'price')
1053
+ average = self.safe_string(order, 'averagePrice')
1054
+ status = self.parse_order_status(self.safe_string(order, 'state'))
1055
+ feeCostString = self.safe_string(order, 'fee')
1056
+ amount = self.safe_string(order, 'size')
1057
+ leverage = self.safe_string(order, 'leverage', '1')
1058
+ contractSize = self.safe_string(market, 'contractSize')
1059
+ baseAmount = Precise.string_mul(contractSize, filled)
1060
+ cost: Str = None
1061
+ if average is not None:
1062
+ cost = Precise.string_mul(average, baseAmount)
1063
+ cost = Precise.string_div(cost, leverage)
1064
+ # spot market buy: "sz" can refer either to base currency units or to quote currency units
1065
+ fee = None
1066
+ if feeCostString is not None:
1067
+ feeCostSigned = Precise.string_abs(feeCostString)
1068
+ feeCurrencyId = self.safe_string(order, 'feeCcy', 'USDT')
1069
+ feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1070
+ fee = {
1071
+ 'cost': self.parse_number(feeCostSigned),
1072
+ 'currency': feeCurrencyCode,
1073
+ }
1074
+ clientOrderId = self.safe_string(order, 'clientOrderId')
1075
+ if (clientOrderId is not None) and (len(clientOrderId) < 1):
1076
+ clientOrderId = None # fix empty clientOrderId string
1077
+ stopLossTriggerPrice = self.safe_number(order, 'slTriggerPrice')
1078
+ stopLossPrice = self.safe_number(order, 'slOrderPrice')
1079
+ takeProfitTriggerPrice = self.safe_number(order, 'tpTriggerPrice')
1080
+ takeProfitPrice = self.safe_number(order, 'tpOrderPrice')
1081
+ reduceOnlyRaw = self.safe_string(order, 'reduceOnly')
1082
+ reduceOnly = (reduceOnlyRaw == 'true')
1083
+ return self.safe_order({
1084
+ 'info': order,
1085
+ 'id': id,
1086
+ 'clientOrderId': clientOrderId,
1087
+ 'timestamp': timestamp,
1088
+ 'datetime': self.iso8601(timestamp),
1089
+ 'lastTradeTimestamp': lastTradeTimestamp,
1090
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
1091
+ 'symbol': symbol,
1092
+ 'type': type,
1093
+ 'timeInForce': timeInForce,
1094
+ 'postOnly': postOnly,
1095
+ 'side': side,
1096
+ 'price': price,
1097
+ 'stopLossTriggerPrice': stopLossTriggerPrice,
1098
+ 'takeProfitTriggerPrice': takeProfitTriggerPrice,
1099
+ 'stopLossPrice': stopLossPrice,
1100
+ 'takeProfitPrice': takeProfitPrice,
1101
+ 'average': average,
1102
+ 'cost': cost,
1103
+ 'amount': amount,
1104
+ 'filled': filled,
1105
+ 'remaining': None,
1106
+ 'status': status,
1107
+ 'fee': fee,
1108
+ 'trades': None,
1109
+ 'reduceOnly': reduceOnly,
1110
+ }, market)
1111
+
1112
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
1113
+ """
1114
+ create a trade order
1115
+ :see: https://blofin.com/docs#place-order
1116
+ :see: https://blofin.com/docs#place-tpsl-order
1117
+ :param str symbol: unified symbol of the market to create an order in
1118
+ :param str type: 'market' or 'limit' or 'post_only' or 'ioc' or 'fok'
1119
+ :param str side: 'buy' or 'sell'
1120
+ :param float amount: how much of currency you want to trade in units of base currency
1121
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1122
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1123
+ :param bool [params.reduceOnly]: a mark to reduce the position size for margin, swap and future orders
1124
+ :param bool [params.postOnly]: True to place a post only order
1125
+ :param str [params.marginMode]: 'cross' or 'isolated', default is 'cross'
1126
+ :param float [params.stopLossPrice]: stop loss trigger price(will use privatePostTradeOrderTpsl)
1127
+ :param float [params.takeProfitPrice]: take profit trigger price(will use privatePostTradeOrderTpsl)
1128
+ :param str [param.positionSide]: *stopLossPrice/takeProfitPrice orders only* 'long' or 'short' or 'net' default is 'net'
1129
+ :param str [params.clientOrderId]: a unique id for the order
1130
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered
1131
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
1132
+ :param float [params.takeProfit.price]: take profit order price(if not provided the order will be a market order)
1133
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
1134
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
1135
+ :param float [params.stopLoss.price]: stop loss order price(if not provided the order will be a market order)
1136
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1137
+ """
1138
+ await self.load_markets()
1139
+ market = self.market(symbol)
1140
+ tpsl = self.safe_bool(params, 'tpsl', False)
1141
+ params = self.omit(params, 'tpsl')
1142
+ method = None
1143
+ method, params = self.handle_option_and_params(params, 'createOrder', 'method', 'privatePostTradeOrder')
1144
+ isStopLossPriceDefined = self.safe_string(params, 'stopLossPrice') is not None
1145
+ isTakeProfitPriceDefined = self.safe_string(params, 'takeProfitPrice') is not None
1146
+ isType2Order = (isStopLossPriceDefined or isTakeProfitPriceDefined)
1147
+ response = None
1148
+ if tpsl or (method == 'privatePostTradeOrderTpsl') or isType2Order:
1149
+ tpslRequest = self.create_tpsl_order_request(symbol, type, side, amount, price, params)
1150
+ response = await self.privatePostTradeOrderTpsl(tpslRequest)
1151
+ else:
1152
+ request = self.create_order_request(symbol, type, side, amount, price, params)
1153
+ response = await self.privatePostTradeOrder(request)
1154
+ data = self.safe_list(response, 'data', [])
1155
+ first = self.safe_dict(data, 0)
1156
+ order = self.parse_order(first, market)
1157
+ order['type'] = type
1158
+ order['side'] = side
1159
+ return order
1160
+
1161
+ def create_tpsl_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
1162
+ market = self.market(symbol)
1163
+ positionSide = self.safe_string(params, 'positionSide', 'net')
1164
+ request: dict = {
1165
+ 'instId': market['id'],
1166
+ 'side': side,
1167
+ 'positionSide': positionSide,
1168
+ 'brokerId': self.safe_string(self.options, 'brokerId', 'ec6dd3a7dd982d0b'),
1169
+ }
1170
+ if amount is not None:
1171
+ request['size'] = self.amount_to_precision(symbol, amount)
1172
+ marginMode = self.safe_string(params, 'marginMode', 'cross') # cross or isolated
1173
+ if marginMode != 'cross' and marginMode != 'isolated':
1174
+ raise BadRequest(self.id + ' createTpslOrder() requires a marginMode parameter that must be either cross or isolated')
1175
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
1176
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
1177
+ if stopLossPrice is not None:
1178
+ request['slTriggerPrice'] = self.price_to_precision(symbol, stopLossPrice)
1179
+ if type == 'market':
1180
+ request['slOrderPrice'] = '-1'
1181
+ else:
1182
+ request['slOrderPrice'] = self.price_to_precision(symbol, price)
1183
+ elif takeProfitPrice is not None:
1184
+ request['tpTriggerPrice'] = self.price_to_precision(symbol, takeProfitPrice)
1185
+ if type == 'market':
1186
+ request['tpOrderPrice'] = '-1'
1187
+ else:
1188
+ request['tpOrderPrice'] = self.price_to_precision(symbol, price)
1189
+ request['marginMode'] = marginMode
1190
+ params = self.omit(params, ['stopLossPrice', 'takeProfitPrice'])
1191
+ return self.extend(request, params)
1192
+
1193
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
1194
+ """
1195
+ cancels an open order
1196
+ :see: https://blofin.com/docs#cancel-order
1197
+ :see: https://blofin.com/docs#cancel-tpsl-order
1198
+ :param str id: order id
1199
+ :param str symbol: unified symbol of the market the order was made in
1200
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1201
+ :param boolean [params.trigger]: True if cancelling a trigger/conditional order/tp sl orders
1202
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1203
+ """
1204
+ if symbol is None:
1205
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
1206
+ await self.load_markets()
1207
+ market = self.market(symbol)
1208
+ request: dict = {
1209
+ 'instId': market['id'],
1210
+ }
1211
+ isTrigger = self.safe_bool_n(params, ['stop', 'trigger', 'tpsl'], False)
1212
+ clientOrderId = self.safe_string(params, 'clientOrderId')
1213
+ if clientOrderId is not None:
1214
+ request['clientOrderId'] = clientOrderId
1215
+ else:
1216
+ if not isTrigger:
1217
+ request['orderId'] = str(id)
1218
+ else:
1219
+ request['tpslId'] = str(id)
1220
+ query = self.omit(params, ['orderId', 'clientOrderId', 'stop', 'trigger', 'tpsl'])
1221
+ if isTrigger:
1222
+ tpslResponse = await self.cancel_orders([id], symbol, params)
1223
+ first = self.safe_dict(tpslResponse, 0)
1224
+ return first
1225
+ response = await self.privatePostTradeCancelOrder(self.extend(request, query))
1226
+ data = self.safe_list(response, 'data', [])
1227
+ order = self.safe_dict(data, 0)
1228
+ return self.parse_order(order, market)
1229
+
1230
+ async def create_orders(self, orders: List[OrderRequest], params={}) -> List[Order]:
1231
+ """
1232
+ create a list of trade orders
1233
+ :see: https://blofin.com/docs#place-multiple-orders
1234
+ :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
1235
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1236
+ """
1237
+ await self.load_markets()
1238
+ ordersRequests = []
1239
+ for i in range(0, len(orders)):
1240
+ rawOrder = orders[i]
1241
+ marketId = self.safe_string(rawOrder, 'symbol')
1242
+ type = self.safe_string(rawOrder, 'type')
1243
+ side = self.safe_string(rawOrder, 'side')
1244
+ amount = self.safe_value(rawOrder, 'amount')
1245
+ price = self.safe_value(rawOrder, 'price')
1246
+ orderParams = self.safe_dict(rawOrder, 'params', {})
1247
+ extendedParams = self.extend(orderParams, params) # the request does not accept extra params since it's a list, so we're extending each order with the common params
1248
+ orderRequest = self.create_order_request(marketId, type, side, amount, price, extendedParams)
1249
+ ordersRequests.append(orderRequest)
1250
+ response = await self.privatePostTradeBatchOrders(ordersRequests)
1251
+ data = self.safe_list(response, 'data', [])
1252
+ return self.parse_orders(data)
1253
+
1254
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1255
+ """
1256
+ Fetch orders that are still open
1257
+ :see: https://blofin.com/docs#get-active-orders
1258
+ :see: https://blofin.com/docs#get-active-tpsl-orders
1259
+ :param str symbol: unified market symbol
1260
+ :param int [since]: the earliest time in ms to fetch open orders for
1261
+ :param int [limit]: the maximum number of open orders structures to retrieve
1262
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1263
+ :param bool [params.stop]: True if fetching trigger or conditional orders
1264
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1265
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1266
+ """
1267
+ await self.load_markets()
1268
+ paginate = False
1269
+ paginate, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'paginate')
1270
+ if paginate:
1271
+ return await self.fetch_paginated_call_dynamic('fetchOpenOrders', symbol, since, limit, params)
1272
+ request: dict = {
1273
+ }
1274
+ market = None
1275
+ if symbol is not None:
1276
+ market = self.market(symbol)
1277
+ request['instId'] = market['id']
1278
+ if limit is not None:
1279
+ request['limit'] = limit # default 100, max 100
1280
+ isStop = self.safe_bool_n(params, ['stop', 'trigger', 'tpsl', 'TPSL'], False)
1281
+ method: Str = None
1282
+ method, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'method', 'privateGetTradeOrdersPending')
1283
+ query = self.omit(params, ['method', 'stop', 'trigger', 'tpsl', 'TPSL'])
1284
+ response = None
1285
+ if isStop or (method == 'privateGetTradeOrdersTpslPending'):
1286
+ response = await self.privateGetTradeOrdersTpslPending(self.extend(request, query))
1287
+ else:
1288
+ response = await self.privateGetTradeOrdersPending(self.extend(request, query))
1289
+ data = self.safe_list(response, 'data', [])
1290
+ return self.parse_orders(data, market, since, limit)
1291
+
1292
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1293
+ """
1294
+ fetch all trades made by the user
1295
+ :see: https://blofin.com/docs#get-trade-history
1296
+ :param str symbol: unified market symbol
1297
+ :param int [since]: the earliest time in ms to fetch trades for
1298
+ :param int [limit]: the maximum number of trades structures to retrieve
1299
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1300
+ :param int [params.until]: Timestamp in ms of the latest time to retrieve trades for
1301
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1302
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1303
+ """
1304
+ await self.load_markets()
1305
+ paginate = False
1306
+ paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
1307
+ if paginate:
1308
+ return await self.fetch_paginated_call_dynamic('fetchMyTrades', symbol, since, limit, params)
1309
+ request: dict = {
1310
+ }
1311
+ market = None
1312
+ if symbol is not None:
1313
+ market = self.market(symbol)
1314
+ request['instId'] = market['id']
1315
+ request, params = self.handle_until_option('end', request, params)
1316
+ if limit is not None:
1317
+ request['limit'] = limit # default 100, max 100
1318
+ response = await self.privateGetTradeFillsHistory(self.extend(request, params))
1319
+ data = self.safe_list(response, 'data', [])
1320
+ return self.parse_trades(data, market, since, limit)
1321
+
1322
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1323
+ """
1324
+ fetch all deposits made to an account
1325
+ :see: https://blofin.com/docs#get-deposite-history
1326
+ :param str code: unified currency code
1327
+ :param int [since]: the earliest time in ms to fetch deposits for
1328
+ :param int [limit]: the maximum number of deposits structures to retrieve
1329
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1330
+ :param int [params.until]: the latest time in ms to fetch entries for
1331
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1332
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1333
+ """
1334
+ await self.load_markets()
1335
+ paginate = False
1336
+ paginate, params = self.handle_option_and_params(params, 'fetchDeposits', 'paginate')
1337
+ if paginate:
1338
+ return await self.fetch_paginated_call_dynamic('fetchDeposits', code, since, limit, params)
1339
+ request: dict = {
1340
+ }
1341
+ currency = None
1342
+ if code is not None:
1343
+ currency = self.currency(code)
1344
+ request['currency'] = currency['id']
1345
+ if since is not None:
1346
+ request['before'] = max(since - 1, 0)
1347
+ if limit is not None:
1348
+ request['limit'] = limit # default 100, max 100
1349
+ request, params = self.handle_until_option('after', request, params)
1350
+ response = await self.privateGetAssetDepositHistory(self.extend(request, params))
1351
+ data = self.safe_list(response, 'data', [])
1352
+ return self.parse_transactions(data, currency, since, limit, params)
1353
+
1354
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1355
+ """
1356
+ fetch all withdrawals made from an account
1357
+ :see: https://blofin.com/docs#get-withdraw-history
1358
+ :param str code: unified currency code
1359
+ :param int [since]: the earliest time in ms to fetch withdrawals for
1360
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
1361
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1362
+ :param int [params.until]: the latest time in ms to fetch entries for
1363
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1364
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1365
+ """
1366
+ await self.load_markets()
1367
+ paginate = False
1368
+ paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
1369
+ if paginate:
1370
+ return await self.fetch_paginated_call_dynamic('fetchWithdrawals', code, since, limit, params)
1371
+ request: dict = {
1372
+ }
1373
+ currency = None
1374
+ if code is not None:
1375
+ currency = self.currency(code)
1376
+ request['currency'] = currency['id']
1377
+ if since is not None:
1378
+ request['before'] = max(since - 1, 0)
1379
+ if limit is not None:
1380
+ request['limit'] = limit # default 100, max 100
1381
+ request, params = self.handle_until_option('after', request, params)
1382
+ response = await self.privateGetAssetWithdrawalHistory(self.extend(request, params))
1383
+ data = self.safe_list(response, 'data', [])
1384
+ return self.parse_transactions(data, currency, since, limit, params)
1385
+
1386
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
1387
+ """
1388
+ fetch the history of changes, actions done by the user or operations that altered balance of the user
1389
+ :see: https://blofin.com/docs#get-funds-transfer-history
1390
+ :param str code: unified currency code, default is None
1391
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
1392
+ :param int [limit]: max number of ledger entrys to return, default is None
1393
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1394
+ :param str [params.marginMode]: 'cross' or 'isolated'
1395
+ :param int [params.until]: the latest time in ms to fetch entries for
1396
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1397
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
1398
+ """
1399
+ await self.load_markets()
1400
+ paginate = False
1401
+ paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
1402
+ if paginate:
1403
+ return await self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params)
1404
+ request: dict = {
1405
+ }
1406
+ if limit is not None:
1407
+ request['limit'] = limit
1408
+ currency = None
1409
+ if code is not None:
1410
+ currency = self.currency(code)
1411
+ request['currency'] = currency['id']
1412
+ request, params = self.handle_until_option('end', request, params)
1413
+ response = None
1414
+ response = await self.privateGetAssetBills(self.extend(request, params))
1415
+ data = self.safe_list(response, 'data', [])
1416
+ return self.parse_ledger(data, currency, since, limit)
1417
+
1418
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
1419
+ #
1420
+ #
1421
+ # fetchDeposits
1422
+ #
1423
+ # {
1424
+ # "currency": "USDT",
1425
+ # "chain": "TRC20",
1426
+ # "address": "TGfJLtnsh3B9EqekFEBZ1nR14QanBUf5Bi",
1427
+ # "txId": "892f4e0c32268b29b2e541ef30d32a30bbf10f902adcc4b1428319ed7c3758fd",
1428
+ # "type": "0",
1429
+ # "amount": "86.975843",
1430
+ # "state": "1",
1431
+ # "ts": "1703163304153",
1432
+ # "tag": null,
1433
+ # "confirm": "16",
1434
+ # "depositId": "36c8e2a7ea184a219de72215a696acaf"
1435
+ # }
1436
+ # fetchWithdrawals
1437
+ # {
1438
+ # "currency": "USDT",
1439
+ # "chain": "TRC20",
1440
+ # "address": "TYgB3sVXHPEDQUu288EG1uMFh9Pk2swLgW",
1441
+ # "txId": "1fd5ac52df414d7ea66194cadd9a5b4d2422c2b9720037f66d98207f9858fd96",
1442
+ # "type": "0",
1443
+ # "amount": "9",
1444
+ # "fee": "1",
1445
+ # "feeCurrency": "USDT",
1446
+ # "state": "3",
1447
+ # "clientId": null,
1448
+ # "ts": "1707217439351",
1449
+ # "tag": null,
1450
+ # "memo": null,
1451
+ # "withdrawId": "e0768698cfdf4aee8e54654c3775914b"
1452
+ # }
1453
+ #
1454
+ type = None
1455
+ id = None
1456
+ withdrawalId = self.safe_string(transaction, 'withdrawId')
1457
+ depositId = self.safe_string(transaction, 'depositId')
1458
+ addressTo = self.safe_string(transaction, 'address')
1459
+ address = addressTo
1460
+ tagTo = self.safe_string(transaction, 'tag')
1461
+ if withdrawalId is not None:
1462
+ type = 'withdrawal'
1463
+ id = withdrawalId
1464
+ else:
1465
+ id = depositId
1466
+ type = 'deposit'
1467
+ currencyId = self.safe_string(transaction, 'currency')
1468
+ code = self.safe_currency_code(currencyId)
1469
+ amount = self.safe_number(transaction, 'amount')
1470
+ status = self.parse_transaction_status(self.safe_string(transaction, 'state'))
1471
+ txid = self.safe_string(transaction, 'txId')
1472
+ timestamp = self.safe_integer(transaction, 'ts')
1473
+ feeCurrencyId = self.safe_string(transaction, 'feeCurrency')
1474
+ feeCode = self.safe_currency_code(feeCurrencyId)
1475
+ feeCost = self.safe_number(transaction, 'fee')
1476
+ return {
1477
+ 'info': transaction,
1478
+ 'id': id,
1479
+ 'currency': code,
1480
+ 'amount': amount,
1481
+ 'network': None,
1482
+ 'addressFrom': None,
1483
+ 'addressTo': addressTo,
1484
+ 'address': address,
1485
+ 'tagFrom': None,
1486
+ 'tagTo': tagTo,
1487
+ 'tag': tagTo,
1488
+ 'status': status,
1489
+ 'type': type,
1490
+ 'updated': None,
1491
+ 'txid': txid,
1492
+ 'timestamp': timestamp,
1493
+ 'datetime': self.iso8601(timestamp),
1494
+ 'internal': None,
1495
+ 'comment': None,
1496
+ 'fee': {
1497
+ 'currency': feeCode,
1498
+ 'cost': feeCost,
1499
+ },
1500
+ }
1501
+
1502
+ def parse_transaction_status(self, status: Str):
1503
+ statuses: dict = {
1504
+ '0': 'pending',
1505
+ '1': 'ok',
1506
+ '2': 'failed',
1507
+ '3': 'pending',
1508
+ }
1509
+ return self.safe_string(statuses, status, status)
1510
+
1511
+ def parse_ledger_entry_type(self, type):
1512
+ types: dict = {
1513
+ '1': 'transfer', # transfer
1514
+ '2': 'trade', # trade
1515
+ '3': 'trade', # delivery
1516
+ '4': 'rebate', # auto token conversion
1517
+ '5': 'trade', # liquidation
1518
+ '6': 'transfer', # margin transfer
1519
+ '7': 'trade', # interest deduction
1520
+ '8': 'fee', # funding rate
1521
+ '9': 'trade', # adl
1522
+ '10': 'trade', # clawback
1523
+ '11': 'trade', # system token conversion
1524
+ }
1525
+ return self.safe_string(types, type, type)
1526
+
1527
+ def parse_ledger_entry(self, item: dict, currency: Currency = None):
1528
+ id = self.safe_string(item, 'transferId')
1529
+ referenceId = self.safe_string(item, 'clientId')
1530
+ fromAccount = self.safe_string(item, 'fromAccount')
1531
+ toAccount = self.safe_string(item, 'toAccount')
1532
+ type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
1533
+ code = self.safe_currency_code(self.safe_string(item, 'currency'), currency)
1534
+ amountString = self.safe_string(item, 'amount')
1535
+ amount = self.parse_number(amountString)
1536
+ timestamp = self.safe_integer(item, 'ts')
1537
+ status = 'ok'
1538
+ return {
1539
+ 'id': id,
1540
+ 'info': item,
1541
+ 'timestamp': timestamp,
1542
+ 'datetime': self.iso8601(timestamp),
1543
+ 'fromAccount': fromAccount,
1544
+ 'toAccount': toAccount,
1545
+ 'type': type,
1546
+ 'currency': code,
1547
+ 'amount': amount,
1548
+ 'clientId': referenceId, # balance before
1549
+ 'status': status,
1550
+ }
1551
+
1552
+ def parse_ids(self, ids):
1553
+ """
1554
+ * @ignore
1555
+ :param string[]|str ids: order ids
1556
+ :returns str[]: list of order ids
1557
+ """
1558
+ if isinstance(ids, str):
1559
+ return ids.split(',')
1560
+ else:
1561
+ return ids
1562
+
1563
+ async def cancel_orders(self, ids, symbol: Str = None, params={}):
1564
+ """
1565
+ cancel multiple orders
1566
+ :see: https://blofin.com/docs#cancel-multiple-orders
1567
+ :param str[] ids: order ids
1568
+ :param str symbol: unified market symbol
1569
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1570
+ :param boolean [params.trigger]: whether the order is a stop/trigger order
1571
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1572
+ """
1573
+ # TODO : the original endpoint signature differs, according to that you can skip individual symbol and assign ids in batch. At self moment, `params` is not being used too.
1574
+ if symbol is None:
1575
+ raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
1576
+ await self.load_markets()
1577
+ market = self.market(symbol)
1578
+ request = []
1579
+ options = self.safe_dict(self.options, 'cancelOrders', {})
1580
+ defaultMethod = self.safe_string(options, 'method', 'privatePostTradeCancelBatchOrders')
1581
+ method = self.safe_string(params, 'method', defaultMethod)
1582
+ clientOrderIds = self.parse_ids(self.safe_value(params, 'clientOrderId'))
1583
+ tpslIds = self.parse_ids(self.safe_value(params, 'tpslId'))
1584
+ stop = self.safe_bool_n(params, ['stop', 'trigger', 'tpsl'])
1585
+ if stop:
1586
+ method = 'privatePostTradeCancelTpsl'
1587
+ if clientOrderIds is None:
1588
+ ids = self.parse_ids(ids)
1589
+ if tpslIds is not None:
1590
+ for i in range(0, len(tpslIds)):
1591
+ request.append({
1592
+ 'tpslId': tpslIds[i],
1593
+ 'instId': market['id'],
1594
+ })
1595
+ for i in range(0, len(ids)):
1596
+ if stop:
1597
+ request.append({
1598
+ 'tpslId': ids[i],
1599
+ 'instId': market['id'],
1600
+ })
1601
+ else:
1602
+ request.append({
1603
+ 'orderId': ids[i],
1604
+ 'instId': market['id'],
1605
+ })
1606
+ else:
1607
+ for i in range(0, len(clientOrderIds)):
1608
+ request.append({
1609
+ 'instId': market['id'],
1610
+ 'clientOrderId': clientOrderIds[i],
1611
+ })
1612
+ response = None
1613
+ if method == 'privatePostTradeCancelTpsl':
1614
+ response = await self.privatePostTradeCancelTpsl(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
1615
+ else:
1616
+ response = await self.privatePostTradeCancelBatchOrders(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
1617
+ ordersData = self.safe_list(response, 'data', [])
1618
+ return self.parse_orders(ordersData, market, None, None, params)
1619
+
1620
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
1621
+ """
1622
+ transfer currency internally between wallets on the same account
1623
+ :see: https://blofin.com/docs#funds-transfer
1624
+ :param str code: unified currency code
1625
+ :param float amount: amount to transfer
1626
+ :param str fromAccount: account to transfer from(funding, swap, copy_trading, earn)
1627
+ :param str toAccount: account to transfer to(funding, swap, copy_trading, earn)
1628
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1629
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
1630
+ """
1631
+ await self.load_markets()
1632
+ currency = self.currency(code)
1633
+ accountsByType = self.safe_dict(self.options, 'accountsByType', {})
1634
+ fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
1635
+ toId = self.safe_string(accountsByType, toAccount, toAccount)
1636
+ request: dict = {
1637
+ 'currency': currency['id'],
1638
+ 'amount': self.currency_to_precision(code, amount),
1639
+ 'fromAccount': fromId,
1640
+ 'toAccount': toId,
1641
+ }
1642
+ response = await self.privatePostAssetTransfer(self.extend(request, params))
1643
+ data = self.safe_dict(response, 'data', {})
1644
+ return self.parse_transfer(data, currency)
1645
+
1646
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
1647
+ id = self.safe_string(transfer, 'transferId')
1648
+ return {
1649
+ 'info': transfer,
1650
+ 'id': id,
1651
+ 'timestamp': None,
1652
+ 'datetime': None,
1653
+ 'currency': None,
1654
+ 'amount': None,
1655
+ 'fromAccount': None,
1656
+ 'toAccount': None,
1657
+ 'status': None,
1658
+ }
1659
+
1660
+ async def fetch_position(self, symbol: str, params={}) -> Position:
1661
+ """
1662
+ fetch data on a single open contract trade position
1663
+ :see: https://blofin.com/docs#get-positions
1664
+ :param str symbol: unified market symbol of the market the position is held in, default is None
1665
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1666
+ :param str [params.instType]: MARGIN, SWAP, FUTURES, OPTION
1667
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1668
+ """
1669
+ await self.load_markets()
1670
+ market = self.market(symbol)
1671
+ request: dict = {
1672
+ 'instId': market['id'],
1673
+ }
1674
+ response = await self.privateGetAccountPositions(self.extend(request, params))
1675
+ data = self.safe_list(response, 'data', [])
1676
+ position = self.safe_dict(data, 0)
1677
+ if position is None:
1678
+ return None
1679
+ return self.parse_position(position, market)
1680
+
1681
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
1682
+ """
1683
+ fetch data on a single open contract trade position
1684
+ :see: https://blofin.com/docs#get-positions
1685
+ :param str[] [symbols]: list of unified market symbols
1686
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1687
+ :param str [params.instType]: MARGIN, SWAP, FUTURES, OPTION
1688
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1689
+ """
1690
+ await self.load_markets()
1691
+ symbols = self.market_symbols(symbols)
1692
+ response = await self.privateGetAccountPositions(params)
1693
+ data = self.safe_list(response, 'data', [])
1694
+ result = self.parse_positions(data)
1695
+ return self.filter_by_array_positions(result, 'symbol', symbols, False)
1696
+
1697
+ def parse_position(self, position: dict, market: Market = None):
1698
+ marketId = self.safe_string(position, 'instId')
1699
+ market = self.safe_market(marketId, market)
1700
+ symbol = market['symbol']
1701
+ pos = self.safe_string(position, 'positions')
1702
+ contractsAbs = Precise.string_abs(pos)
1703
+ side = self.safe_string(position, 'positionSide')
1704
+ hedged = side != 'net'
1705
+ contracts = self.parse_number(contractsAbs)
1706
+ if pos is not None:
1707
+ if side == 'net':
1708
+ if Precise.string_gt(pos, '0'):
1709
+ side = 'long'
1710
+ elif Precise.string_lt(pos, '0'):
1711
+ side = 'short'
1712
+ else:
1713
+ side = None
1714
+ contractSize = self.safe_number(market, 'contractSize')
1715
+ contractSizeString = self.number_to_string(contractSize)
1716
+ markPriceString = self.safe_string(position, 'markPrice')
1717
+ notionalString = self.safe_string(position, 'notionalUsd')
1718
+ if market['inverse']:
1719
+ notionalString = Precise.string_div(Precise.string_mul(contractsAbs, contractSizeString), markPriceString)
1720
+ notional = self.parse_number(notionalString)
1721
+ marginMode = self.safe_string(position, 'marginMode')
1722
+ initialMarginString = None
1723
+ entryPriceString = self.safe_string(position, 'averagePrice')
1724
+ unrealizedPnlString = self.safe_string(position, 'unrealizedPnl')
1725
+ leverageString = self.safe_string(position, 'leverage')
1726
+ initialMarginPercentage = None
1727
+ collateralString = None
1728
+ if marginMode == 'cross':
1729
+ initialMarginString = self.safe_string(position, 'initialMargin')
1730
+ collateralString = Precise.string_add(initialMarginString, unrealizedPnlString)
1731
+ elif marginMode == 'isolated':
1732
+ initialMarginPercentage = Precise.string_div('1', leverageString)
1733
+ collateralString = self.safe_string(position, 'margin')
1734
+ maintenanceMarginString = self.safe_string(position, 'maintenanceMargin')
1735
+ maintenanceMargin = self.parse_number(maintenanceMarginString)
1736
+ maintenanceMarginPercentageString = Precise.string_div(maintenanceMarginString, notionalString)
1737
+ if initialMarginPercentage is None:
1738
+ initialMarginPercentage = self.parse_number(Precise.string_div(initialMarginString, notionalString, 4))
1739
+ elif initialMarginString is None:
1740
+ initialMarginString = Precise.string_mul(initialMarginPercentage, notionalString)
1741
+ rounder = '0.00005' # round to closest 0.01%
1742
+ maintenanceMarginPercentage = self.parse_number(Precise.string_div(Precise.string_add(maintenanceMarginPercentageString, rounder), '1', 4))
1743
+ liquidationPrice = self.safe_number(position, 'liquidationPrice')
1744
+ percentageString = self.safe_string(position, 'unrealizedPnlRatio')
1745
+ percentage = self.parse_number(Precise.string_mul(percentageString, '100'))
1746
+ timestamp = self.safe_integer(position, 'updateTime')
1747
+ marginRatio = self.parse_number(Precise.string_div(maintenanceMarginString, collateralString, 4))
1748
+ return self.safe_position({
1749
+ 'info': position,
1750
+ 'id': None,
1751
+ 'symbol': symbol,
1752
+ 'notional': notional,
1753
+ 'marginMode': marginMode,
1754
+ 'liquidationPrice': liquidationPrice,
1755
+ 'entryPrice': self.parse_number(entryPriceString),
1756
+ 'unrealizedPnl': self.parse_number(unrealizedPnlString),
1757
+ 'percentage': percentage,
1758
+ 'contracts': contracts,
1759
+ 'contractSize': contractSize,
1760
+ 'markPrice': self.parse_number(markPriceString),
1761
+ 'lastPrice': None,
1762
+ 'side': side,
1763
+ 'hedged': hedged,
1764
+ 'timestamp': timestamp,
1765
+ 'datetime': self.iso8601(timestamp),
1766
+ 'lastUpdateTimestamp': None,
1767
+ 'maintenanceMargin': maintenanceMargin,
1768
+ 'maintenanceMarginPercentage': maintenanceMarginPercentage,
1769
+ 'collateral': self.parse_number(collateralString),
1770
+ 'initialMargin': self.parse_number(initialMarginString),
1771
+ 'initialMarginPercentage': self.parse_number(initialMarginPercentage),
1772
+ 'leverage': self.parse_number(leverageString),
1773
+ 'marginRatio': marginRatio,
1774
+ 'stopLossPrice': None,
1775
+ 'takeProfitPrice': None,
1776
+ })
1777
+
1778
+ async def fetch_leverages(self, symbols: Strings = None, params={}) -> Leverages:
1779
+ """
1780
+ fetch the set leverage for all contract markets
1781
+ :see: https://docs.blofin.com/index.html#get-multiple-leverage
1782
+ :param str[] symbols: a list of unified market symbols, required on blofin
1783
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1784
+ :param str [params.marginMode]: 'cross' or 'isolated'
1785
+ :returns dict: a list of `leverage structures <https://docs.ccxt.com/#/?id=leverage-structure>`
1786
+ """
1787
+ await self.load_markets()
1788
+ if symbols is None:
1789
+ raise ArgumentsRequired(self.id + ' fetchLeverages() requires a symbols argument')
1790
+ marginMode = None
1791
+ marginMode, params = self.handle_margin_mode_and_params('fetchLeverages', params)
1792
+ if marginMode is None:
1793
+ marginMode = self.safe_string(params, 'marginMode', 'cross') # cross marginMode
1794
+ if (marginMode != 'cross') and (marginMode != 'isolated'):
1795
+ raise BadRequest(self.id + ' fetchLeverages() requires a marginMode parameter that must be either cross or isolated')
1796
+ symbols = self.market_symbols(symbols)
1797
+ instIds = ''
1798
+ for i in range(0, len(symbols)):
1799
+ entry = symbols[i]
1800
+ entryMarket = self.market(entry)
1801
+ if i > 0:
1802
+ instIds = instIds + ',' + entryMarket['id']
1803
+ else:
1804
+ instIds = instIds + entryMarket['id']
1805
+ request: dict = {
1806
+ 'instId': instIds,
1807
+ 'marginMode': marginMode,
1808
+ }
1809
+ response = await self.privateGetAccountBatchLeverageInfo(self.extend(request, params))
1810
+ #
1811
+ # {
1812
+ # "code": "0",
1813
+ # "msg": "success",
1814
+ # "data": [
1815
+ # {
1816
+ # "leverage": "3",
1817
+ # "marginMode": "cross",
1818
+ # "instId": "BTC-USDT"
1819
+ # },
1820
+ # ]
1821
+ # }
1822
+ #
1823
+ leverages = self.safe_list(response, 'data', [])
1824
+ return self.parse_leverages(leverages, symbols, 'instId')
1825
+
1826
+ async def fetch_leverage(self, symbol: str, params={}) -> Leverage:
1827
+ """
1828
+ fetch the set leverage for a market
1829
+ :see: https://docs.blofin.com/index.html#get-leverage
1830
+ :param str symbol: unified market symbol
1831
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1832
+ :param str [params.marginMode]: 'cross' or 'isolated'
1833
+ :returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
1834
+ """
1835
+ await self.load_markets()
1836
+ marginMode = None
1837
+ marginMode, params = self.handle_margin_mode_and_params('fetchLeverage', params)
1838
+ if marginMode is None:
1839
+ marginMode = self.safe_string(params, 'marginMode', 'cross') # cross marginMode
1840
+ if (marginMode != 'cross') and (marginMode != 'isolated'):
1841
+ raise BadRequest(self.id + ' fetchLeverage() requires a marginMode parameter that must be either cross or isolated')
1842
+ market = self.market(symbol)
1843
+ request: dict = {
1844
+ 'instId': market['id'],
1845
+ 'marginMode': marginMode,
1846
+ }
1847
+ response = await self.privateGetAccountLeverageInfo(self.extend(request, params))
1848
+ #
1849
+ # {
1850
+ # "code": "0",
1851
+ # "msg": "success",
1852
+ # "data": {
1853
+ # "leverage": "3",
1854
+ # "marginMode": "cross",
1855
+ # "instId": "BTC-USDT"
1856
+ # }
1857
+ # }
1858
+ #
1859
+ data = self.safe_dict(response, 'data', {})
1860
+ return self.parse_leverage(data, market)
1861
+
1862
+ def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
1863
+ marketId = self.safe_string(leverage, 'instId')
1864
+ leverageValue = self.safe_integer(leverage, 'leverage')
1865
+ return {
1866
+ 'info': leverage,
1867
+ 'symbol': self.safe_symbol(marketId, market),
1868
+ 'marginMode': self.safe_string_lower(leverage, 'marginMode'),
1869
+ 'longLeverage': leverageValue,
1870
+ 'shortLeverage': leverageValue,
1871
+ }
1872
+
1873
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
1874
+ """
1875
+ set the level of leverage for a market
1876
+ :see: https://blofin.com/docs#set-leverage
1877
+ :param int leverage: the rate of leverage
1878
+ :param str symbol: unified market symbol
1879
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1880
+ :param str [params.marginMode]: 'cross' or 'isolated'
1881
+ :returns dict: response from the exchange
1882
+ """
1883
+ if symbol is None:
1884
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
1885
+ # WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
1886
+ # AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
1887
+ if (leverage < 1) or (leverage > 125):
1888
+ raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 125')
1889
+ await self.load_markets()
1890
+ market = self.market(symbol)
1891
+ marginMode = None
1892
+ marginMode, params = self.handle_margin_mode_and_params('setLeverage', params, 'cross')
1893
+ if (marginMode != 'cross') and (marginMode != 'isolated'):
1894
+ raise BadRequest(self.id + ' setLeverage() requires a marginMode parameter that must be either cross or isolated')
1895
+ request: dict = {
1896
+ 'leverage': leverage,
1897
+ 'marginMode': marginMode,
1898
+ 'instId': market['id'],
1899
+ }
1900
+ response = await self.privatePostAccountSetLeverage(self.extend(request, params))
1901
+ return response
1902
+
1903
+ async def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
1904
+ """
1905
+ closes open positions for a market
1906
+ :see: https://blofin.com/docs#close-positions
1907
+ :param str symbol: Unified CCXT market symbol
1908
+ :param str [side]: 'buy' or 'sell', leave in net mode
1909
+ :param dict [params]: extra parameters specific to the blofin api endpoint
1910
+ :param str [params.clientOrderId]: a unique identifier for the order
1911
+ :param str [params.marginMode]: 'cross' or 'isolated', default is 'cross
1912
+ :param str [params.code]: *required in the case of closing cross MARGIN position for Single-currency margin* margin currency
1913
+ *
1914
+ * EXCHANGE SPECIFIC PARAMETERS
1915
+ :param boolean [params.autoCxl]: whether any pending orders for closing out needs to be automatically canceled when close position via a market order. False or True, the default is False
1916
+ :param str [params.tag]: order tag a combination of case-sensitive alphanumerics, all numbers, or all letters of up to 16 characters
1917
+ :returns dict[]: `A list of position structures <https://docs.ccxt.com/#/?id=position-structure>`
1918
+ """
1919
+ await self.load_markets()
1920
+ market = self.market(symbol)
1921
+ clientOrderId = self.safe_string(params, 'clientOrderId')
1922
+ marginMode = None
1923
+ marginMode, params = self.handle_margin_mode_and_params('closePosition', params, 'cross')
1924
+ request: dict = {
1925
+ 'instId': market['id'],
1926
+ 'marginMode': marginMode,
1927
+ }
1928
+ if clientOrderId is not None:
1929
+ request['clientOrderId'] = clientOrderId
1930
+ response = await self.privatePostTradeClosePosition(self.extend(request, params))
1931
+ return self.safe_dict(response, 'data')
1932
+
1933
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1934
+ """
1935
+ fetches information on multiple closed orders made by the user
1936
+ :see: https://blofin.com/docs#get-order-history
1937
+ :see: https://blofin.com/docs#get-tpsl-order-history
1938
+ :param str symbol: unified market symbol of the market orders were made in
1939
+ :param int [since]: the earliest time in ms to fetch orders for
1940
+ :param int [limit]: the maximum number of orde structures to retrieve
1941
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1942
+ :param bool [params.stop]: True if fetching trigger or conditional orders
1943
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1944
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1945
+ """
1946
+ await self.load_markets()
1947
+ paginate = False
1948
+ paginate, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'paginate')
1949
+ if paginate:
1950
+ return await self.fetch_paginated_call_dynamic('fetchClosedOrders', symbol, since, limit, params)
1951
+ request: dict = {
1952
+ }
1953
+ market = None
1954
+ if symbol is not None:
1955
+ market = self.market(symbol)
1956
+ request['instId'] = market['id']
1957
+ if limit is not None:
1958
+ request['limit'] = limit # default 100, max 100
1959
+ if since is not None:
1960
+ request['begin'] = since
1961
+ isStop = self.safe_bool_n(params, ['stop', 'trigger', 'tpsl', 'TPSL'], False)
1962
+ method: Str = None
1963
+ method, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'method', 'privateGetTradeOrdersHistory')
1964
+ query = self.omit(params, ['method', 'stop', 'trigger', 'tpsl', 'TPSL'])
1965
+ response = None
1966
+ if (isStop) or (method == 'privateGetTradeOrdersTpslHistory'):
1967
+ response = await self.privateGetTradeOrdersTpslHistory(self.extend(request, query))
1968
+ else:
1969
+ response = await self.privateGetTradeOrdersHistory(self.extend(request, query))
1970
+ data = self.safe_list(response, 'data', [])
1971
+ return self.parse_orders(data, market, since, limit)
1972
+
1973
+ async def fetch_margin_mode(self, symbol: str, params={}) -> MarginMode:
1974
+ """
1975
+ fetches the margin mode of a trading pair
1976
+ :see: https://docs.blofin.com/index.html#get-margin-mode
1977
+ :param str symbol: unified symbol of the market to fetch the margin mode for
1978
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1979
+ :returns dict: a `margin mode structure <https://docs.ccxt.com/#/?id=margin-mode-structure>`
1980
+ """
1981
+ await self.load_markets()
1982
+ market = self.market(symbol)
1983
+ response = await self.privateGetAccountMarginMode(params)
1984
+ #
1985
+ # {
1986
+ # "code": "0",
1987
+ # "msg": "success",
1988
+ # "data": {
1989
+ # "marginMode": "cross"
1990
+ # }
1991
+ # }
1992
+ #
1993
+ data = self.safe_dict(response, 'data', {})
1994
+ return self.parse_margin_mode(data, market)
1995
+
1996
+ def parse_margin_mode(self, marginMode: dict, market=None) -> MarginMode:
1997
+ return {
1998
+ 'info': marginMode,
1999
+ 'symbol': market['symbol'],
2000
+ 'marginMode': self.safe_string(marginMode, 'marginMode'),
2001
+ }
2002
+
2003
+ def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
2004
+ if response is None:
2005
+ return None # fallback to default error handler
2006
+ #
2007
+ # {"code":"152002","msg":"Parameter bar error."}
2008
+ #
2009
+ code = self.safe_string(response, 'code')
2010
+ message = self.safe_string(response, 'msg')
2011
+ feedback = self.id + ' ' + body
2012
+ if code is not None and code != '0':
2013
+ self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
2014
+ self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
2015
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
2016
+ raise ExchangeError(feedback) # unknown message
2017
+ #
2018
+ # {
2019
+ # orderId: null,
2020
+ # clientOrderId: '',
2021
+ # msg: 'Order failed. Insufficient USDT margin in account',
2022
+ # code: '103003'
2023
+ # }
2024
+ #
2025
+ data = self.safe_list(response, 'data')
2026
+ first = self.safe_dict(data, 0)
2027
+ insideMsg = self.safe_string(first, 'msg')
2028
+ insideCode = self.safe_string(first, 'code')
2029
+ if insideCode is not None and insideCode != '0':
2030
+ self.throw_exactly_matched_exception(self.exceptions['exact'], insideCode, feedback)
2031
+ self.throw_exactly_matched_exception(self.exceptions['exact'], insideMsg, feedback)
2032
+ self.throw_broadly_matched_exception(self.exceptions['broad'], insideMsg, feedback)
2033
+ return None
2034
+
2035
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2036
+ request = '/api/' + self.version + '/' + self.implode_params(path, params)
2037
+ query = self.omit(params, self.extract_params(path))
2038
+ url = self.implode_hostname(self.urls['api']['rest']) + request
2039
+ # type = self.getPathAuthenticationType(path)
2040
+ if api == 'public':
2041
+ if not self.is_empty(query):
2042
+ url += '?' + self.urlencode(query)
2043
+ elif api == 'private':
2044
+ self.check_required_credentials()
2045
+ timestamp = str(self.milliseconds())
2046
+ headers = {
2047
+ 'ACCESS-KEY': self.apiKey,
2048
+ 'ACCESS-PASSPHRASE': self.password,
2049
+ 'ACCESS-TIMESTAMP': timestamp,
2050
+ 'ACCESS-NONCE': timestamp,
2051
+ }
2052
+ sign_body = ''
2053
+ if method == 'GET':
2054
+ if not self.is_empty(query):
2055
+ urlencodedQuery = '?' + self.urlencode(query)
2056
+ url += urlencodedQuery
2057
+ request += urlencodedQuery
2058
+ else:
2059
+ if not self.is_empty(query):
2060
+ body = self.json(query)
2061
+ sign_body = body
2062
+ headers['Content-Type'] = 'application/json'
2063
+ auth = request + method + timestamp + timestamp + sign_body
2064
+ signature = self.string_to_base64(self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256))
2065
+ headers['ACCESS-SIGN'] = signature
2066
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}