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,4473 @@
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.phemex import ImplicitAPI
8
+ import hashlib
9
+ import numbers
10
+ from ccxt.base.types import Balances, Currencies, Currency, Int, LeverageTier, LeverageTiers, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry, TransferEntries
11
+ from typing import List
12
+ from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import AuthenticationError
14
+ from ccxt.base.errors import PermissionDenied
15
+ from ccxt.base.errors import AccountSuspended
16
+ from ccxt.base.errors import ArgumentsRequired
17
+ from ccxt.base.errors import BadRequest
18
+ from ccxt.base.errors import BadSymbol
19
+ from ccxt.base.errors import InsufficientFunds
20
+ from ccxt.base.errors import InvalidOrder
21
+ from ccxt.base.errors import OrderNotFound
22
+ from ccxt.base.errors import CancelPending
23
+ from ccxt.base.errors import DuplicateOrderId
24
+ from ccxt.base.errors import DDoSProtection
25
+ from ccxt.base.errors import RateLimitExceeded
26
+ from ccxt.base.decimal_to_precision import TICK_SIZE
27
+ from ccxt.base.precise import Precise
28
+
29
+
30
+ class phemex(Exchange, ImplicitAPI):
31
+
32
+ def describe(self):
33
+ return self.deep_extend(super(phemex, self).describe(), {
34
+ 'id': 'phemex',
35
+ 'name': 'Phemex',
36
+ 'countries': ['CN'], # China
37
+ 'rateLimit': 120.5,
38
+ 'version': 'v1',
39
+ 'certified': False,
40
+ 'pro': True,
41
+ 'hostname': 'api.phemex.com',
42
+ 'has': {
43
+ 'CORS': None,
44
+ 'spot': True,
45
+ 'margin': False,
46
+ 'swap': True,
47
+ 'future': False,
48
+ 'option': False,
49
+ 'addMargin': False,
50
+ 'cancelAllOrders': True,
51
+ 'cancelOrder': True,
52
+ 'closePosition': False,
53
+ 'createOrder': True,
54
+ 'createReduceOnlyOrder': True,
55
+ 'createStopLimitOrder': True,
56
+ 'createStopMarketOrder': True,
57
+ 'createStopOrder': True,
58
+ 'editOrder': True,
59
+ 'fetchBalance': True,
60
+ 'fetchBorrowRateHistories': False,
61
+ 'fetchBorrowRateHistory': False,
62
+ 'fetchClosedOrders': True,
63
+ 'fetchCrossBorrowRate': False,
64
+ 'fetchCrossBorrowRates': False,
65
+ 'fetchCurrencies': True,
66
+ 'fetchDepositAddress': True,
67
+ 'fetchDeposits': True,
68
+ 'fetchFundingHistory': True,
69
+ 'fetchFundingRate': True,
70
+ 'fetchFundingRateHistories': False,
71
+ 'fetchFundingRateHistory': True,
72
+ 'fetchFundingRates': False,
73
+ 'fetchIndexOHLCV': False,
74
+ 'fetchIsolatedBorrowRate': False,
75
+ 'fetchIsolatedBorrowRates': False,
76
+ 'fetchLeverage': False,
77
+ 'fetchLeverageTiers': True,
78
+ 'fetchMarketLeverageTiers': 'emulated',
79
+ 'fetchMarkets': True,
80
+ 'fetchMarkOHLCV': False,
81
+ 'fetchMyTrades': True,
82
+ 'fetchOHLCV': True,
83
+ 'fetchOpenOrders': True,
84
+ 'fetchOrder': True,
85
+ 'fetchOrderBook': True,
86
+ 'fetchOrders': True,
87
+ 'fetchPositions': True,
88
+ 'fetchPositionsRisk': False,
89
+ 'fetchPremiumIndexOHLCV': False,
90
+ 'fetchTicker': True,
91
+ 'fetchTickers': True,
92
+ 'fetchTrades': True,
93
+ 'fetchTradingFee': False,
94
+ 'fetchTradingFees': False,
95
+ 'fetchTransfers': True,
96
+ 'fetchWithdrawals': True,
97
+ 'reduceMargin': False,
98
+ 'sandbox': True,
99
+ 'setLeverage': True,
100
+ 'setMargin': True,
101
+ 'setMarginMode': True,
102
+ 'setPositionMode': True,
103
+ 'transfer': True,
104
+ 'withdraw': True,
105
+ },
106
+ 'urls': {
107
+ 'logo': 'https://user-images.githubusercontent.com/1294454/85225056-221eb600-b3d7-11ea-930d-564d2690e3f6.jpg',
108
+ 'test': {
109
+ 'v1': 'https://testnet-api.phemex.com/v1',
110
+ 'v2': 'https://testnet-api.phemex.com',
111
+ 'public': 'https://testnet-api.phemex.com/exchange/public',
112
+ 'private': 'https://testnet-api.phemex.com',
113
+ },
114
+ 'api': {
115
+ 'v1': 'https://{hostname}/v1',
116
+ 'v2': 'https://{hostname}',
117
+ 'public': 'https://{hostname}/exchange/public',
118
+ 'private': 'https://{hostname}',
119
+ },
120
+ 'www': 'https://phemex.com',
121
+ 'doc': 'https://github.com/phemex/phemex-api-docs',
122
+ 'fees': 'https://phemex.com/fees-conditions',
123
+ 'referral': {
124
+ 'url': 'https://phemex.com/register?referralCode=EDNVJ',
125
+ 'discount': 0.1,
126
+ },
127
+ },
128
+ 'timeframes': {
129
+ '1m': '60',
130
+ '3m': '180',
131
+ '5m': '300',
132
+ '15m': '900',
133
+ '30m': '1800',
134
+ '1h': '3600',
135
+ '2h': '7200',
136
+ '3h': '10800',
137
+ '4h': '14400',
138
+ '6h': '21600',
139
+ '12h': '43200',
140
+ '1d': '86400',
141
+ '1w': '604800',
142
+ '1M': '2592000',
143
+ '3M': '7776000',
144
+ '1Y': '31104000',
145
+ },
146
+ 'api': {
147
+ 'public': {
148
+ 'get': {
149
+ 'cfg/v2/products': 5, # spot + contracts
150
+ 'cfg/fundingRates': 5,
151
+ 'products': 5, # contracts only
152
+ 'nomics/trades': 5, # ?market=<symbol>&since=<since>
153
+ 'md/kline': 5, # ?from=1589811875&resolution=1800&symbol=sBTCUSDT&to=1592457935
154
+ 'md/v2/kline/list': 5, # perpetual api ?symbol=<symbol>&to=<to>&from=<from>&resolution=<resolution>
155
+ 'md/v2/kline': 5, # ?symbol=<symbol>&resolution=<resolution>&limit=<limit>
156
+ 'md/v2/kline/last': 5, # perpetual ?symbol=<symbol>&resolution=<resolution>&limit=<limit>
157
+ 'md/orderbook': 5, # ?symbol=<symbol>
158
+ 'md/trade': 5, # ?symbol=<symbol>
159
+ 'md/spot/ticker/24hr': 5, # ?symbol=<symbol>
160
+ 'exchange/public/cfg/chain-settings': 5, # ?currency=<currency>
161
+ },
162
+ },
163
+ 'v1': {
164
+ 'get': {
165
+ 'md/fullbook': 5, # ?symbol=<symbol>
166
+ 'md/orderbook': 5, # ?symbol=<symbol>
167
+ 'md/trade': 5, # ?symbol=<symbol>&id=<id>
168
+ 'md/ticker/24hr': 5, # ?symbol=<symbol>&id=<id>
169
+ 'md/ticker/24hr/all': 5, # ?id=<id>
170
+ 'md/spot/ticker/24hr': 5, # ?symbol=<symbol>&id=<id>
171
+ 'md/spot/ticker/24hr/all': 5, # ?symbol=<symbol>&id=<id>
172
+ 'exchange/public/products': 5, # contracts only
173
+ 'api-data/public/data/funding-rate-history': 5,
174
+ },
175
+ },
176
+ 'v2': {
177
+ 'get': {
178
+ 'public/products': 5,
179
+ 'md/v2/orderbook': 5, # ?symbol=<symbol>&id=<id>
180
+ 'md/v2/trade': 5, # ?symbol=<symbol>&id=<id>
181
+ 'md/v2/ticker/24hr': 5, # ?symbol=<symbol>&id=<id>
182
+ 'md/v2/ticker/24hr/all': 5, # ?id=<id>
183
+ 'api-data/public/data/funding-rate-history': 5,
184
+ },
185
+ },
186
+ 'private': {
187
+ 'get': {
188
+ # spot
189
+ 'spot/orders/active': 1, # ?symbol=<symbol>&orderID=<orderID>
190
+ # 'spot/orders/active': 5, # ?symbol=<symbol>&clOrDID=<clOrdID>
191
+ 'spot/orders': 1, # ?symbol=<symbol>
192
+ 'spot/wallets': 5, # ?currency=<currency>
193
+ 'exchange/spot/order': 5, # ?symbol=<symbol>&ordStatus=<ordStatus5,orderStatus2>ordType=<ordType5,orderType2>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
194
+ 'exchange/spot/order/trades': 5, # ?symbol=<symbol>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
195
+ 'exchange/order/v2/orderList': 5, # ?symbol=<symbol>&currency=<currency>&ordStatus=<ordStatus>&ordType=<ordType>&start=<start>&end=<end>&offset=<offset>&limit=<limit>&withCount=<withCount></withCount>
196
+ 'exchange/order/v2/tradingList': 5, # ?symbol=<symbol>&currency=<currency>&execType=<execType>&offset=<offset>&limit=<limit>&withCount=<withCount>
197
+ # swap
198
+ 'accounts/accountPositions': 1, # ?currency=<currency>
199
+ 'g-accounts/accountPositions': 1, # ?currency=<currency>
200
+ 'accounts/positions': 25, # ?currency=<currency>
201
+ 'api-data/futures/funding-fees': 5, # ?symbol=<symbol>
202
+ 'api-data/g-futures/funding-fees': 5, # ?symbol=<symbol>
203
+ 'api-data/futures/orders': 5, # ?symbol=<symbol>
204
+ 'api-data/g-futures/orders': 5, # ?symbol=<symbol>
205
+ 'api-data/futures/orders/by-order-id': 5, # ?symbol=<symbol>
206
+ 'api-data/g-futures/orders/by-order-id': 5, # ?symbol=<symbol>
207
+ 'api-data/futures/trades': 5, # ?symbol=<symbol>
208
+ 'api-data/g-futures/trades': 5, # ?symbol=<symbol>
209
+ 'api-data/futures/trading-fees': 5, # ?symbol=<symbol>
210
+ 'api-data/g-futures/trading-fees': 5, # ?symbol=<symbol>
211
+ 'api-data/futures/v2/tradeAccountDetail': 5, # ?currency=<currecny>&type=<type>&limit=<limit>&offset=<offset>&start=<start>&end=<end>&withCount=<withCount>
212
+ 'g-orders/activeList': 1, # ?symbol=<symbol>
213
+ 'orders/activeList': 1, # ?symbol=<symbol>
214
+ 'exchange/order/list': 5, # ?symbol=<symbol>&start=<start>&end=<end>&offset=<offset>&limit=<limit>&ordStatus=<ordStatus>&withCount=<withCount>
215
+ 'exchange/order': 5, # ?symbol=<symbol>&orderID=<orderID5,orderID2>
216
+ # 'exchange/order': 5, # ?symbol=<symbol>&clOrdID=<clOrdID5,clOrdID2>
217
+ 'exchange/order/trade': 5, # ?symbol=<symbol>&start=<start>&end=<end>&limit=<limit>&offset=<offset>&withCount=<withCount>
218
+ 'phemex-user/users/children': 5, # ?offset=<offset>&limit=<limit>&withCount=<withCount>
219
+ 'phemex-user/wallets/v2/depositAddress': 5, # ?_t=1592722635531&currency=USDT
220
+ 'phemex-user/wallets/tradeAccountDetail': 5, # ?bizCode=&currency=&end=1642443347321&limit=10&offset=0&side=&start=1&type=4&withCount=true
221
+ 'phemex-deposit/wallets/api/depositAddress': 5, # ?currency=<currency>&chainName=<chainName>
222
+ 'phemex-deposit/wallets/api/depositHist': 5, # ?currency=<currency>&offset=<offset>&limit=<limit>&withCount=<withCount>
223
+ 'phemex-deposit/wallets/api/chainCfg': 5, # ?currency=<currency>
224
+ 'phemex-withdraw/wallets/api/withdrawHist': 5, # ?currency=<currency>&chainName=<chainNameList>&offset=<offset>&limit=<limit>&withCount=<withCount>
225
+ 'phemex-withdraw/wallets/api/asset/info': 5, # ?currency=<currency>&amount=<amount>
226
+ 'phemex-user/order/closedPositionList': 5, # ?currency=USD&limit=10&offset=0&symbol=&withCount=true
227
+ 'exchange/margins/transfer': 5, # ?start=<start>&end=<end>&offset=<offset>&limit=<limit>&withCount=<withCount>
228
+ 'exchange/wallets/confirm/withdraw': 5, # ?code=<withdrawConfirmCode>
229
+ 'exchange/wallets/withdrawList': 5, # ?currency=<currency>&limit=<limit>&offset=<offset>&withCount=<withCount>
230
+ 'exchange/wallets/depositList': 5, # ?currency=<currency>&offset=<offset>&limit=<limit>
231
+ 'exchange/wallets/v2/depositAddress': 5, # ?currency=<currency>
232
+ 'api-data/spots/funds': 5, # ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
233
+ 'api-data/spots/orders': 5, # ?symbol=<symbol>
234
+ 'api-data/spots/orders/by-order-id': 5, # ?symbol=<symbol>&oderId=<orderID>&clOrdID=<clOrdID>
235
+ 'api-data/spots/pnls': 5,
236
+ 'api-data/spots/trades': 5, # ?symbol=<symbol>
237
+ 'api-data/spots/trades/by-order-id': 5, # ?symbol=<symbol>&oderId=<orderID>&clOrdID=<clOrdID>
238
+ 'assets/convert': 5, # ?startTime=<startTime>&endTime=<endTime>&limit=<limit>&offset=<offset>
239
+ # transfer
240
+ 'assets/transfer': 5, # ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
241
+ 'assets/spots/sub-accounts/transfer': 5, # ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
242
+ 'assets/futures/sub-accounts/transfer': 5, # ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
243
+ 'assets/quote': 5, # ?fromCurrency=<currency>&toCurrency=<currency>&amountEv=<amount>
244
+ # deposit/withdraw
245
+ },
246
+ 'post': {
247
+ # spot
248
+ 'spot/orders': 1,
249
+ # swap
250
+ 'orders': 1,
251
+ 'g-orders': 1,
252
+ 'positions/assign': 5, # ?symbol=<symbol>&posBalance=<posBalance>&posBalanceEv=<posBalanceEv>
253
+ 'exchange/wallets/transferOut': 5,
254
+ 'exchange/wallets/transferIn': 5,
255
+ 'exchange/margins': 5,
256
+ 'exchange/wallets/createWithdraw': 5, # ?otpCode=<otpCode>
257
+ 'exchange/wallets/cancelWithdraw': 5,
258
+ 'exchange/wallets/createWithdrawAddress': 5, # ?otpCode={optCode}
259
+ # transfer
260
+ 'assets/transfer': 5,
261
+ 'assets/spots/sub-accounts/transfer': 5, # for sub-account only
262
+ 'assets/futures/sub-accounts/transfer': 5, # for sub-account only
263
+ 'assets/universal-transfer': 5, # for Main account only
264
+ 'assets/convert': 5,
265
+ # withdraw
266
+ 'phemex-withdraw/wallets/api/createWithdraw': 5, # ?currency=<currency>&address=<address>&amount=<amount>&addressTag=<addressTag>&chainName=<chainName>
267
+ 'phemex-withdraw/wallets/api/cancelWithdraw': 5, # ?id=<id>
268
+ },
269
+ 'put': {
270
+ # spot
271
+ 'spot/orders/create': 1, # ?symbol=<symbol>&trigger=<trigger>&clOrdID=<clOrdID>&priceEp=<priceEp>&baseQtyEv=<baseQtyEv>&quoteQtyEv=<quoteQtyEv>&stopPxEp=<stopPxEp>&text=<text>&side=<side>&qtyType=<qtyType>&ordType=<ordType>&timeInForce=<timeInForce>&execInst=<execInst>
272
+ 'spot/orders': 1, # ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&priceEp=<priceEp>&baseQtyEV=<baseQtyEV>&quoteQtyEv=<quoteQtyEv>&stopPxEp=<stopPxEp>
273
+ # swap
274
+ 'orders/replace': 1, # ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&price=<price>&priceEp=<priceEp>&orderQty=<orderQty>&stopPx=<stopPx>&stopPxEp=<stopPxEp>&takeProfit=<takeProfit>&takeProfitEp=<takeProfitEp>&stopLoss=<stopLoss>&stopLossEp=<stopLossEp>&pegOffsetValueEp=<pegOffsetValueEp>&pegPriceType=<pegPriceType>
275
+ 'g-orders/replace': 1, # ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&price=<price>&priceEp=<priceEp>&orderQty=<orderQty>&stopPx=<stopPx>&stopPxEp=<stopPxEp>&takeProfit=<takeProfit>&takeProfitEp=<takeProfitEp>&stopLoss=<stopLoss>&stopLossEp=<stopLossEp>&pegOffsetValueEp=<pegOffsetValueEp>&pegPriceType=<pegPriceType>
276
+ 'positions/leverage': 5, # ?symbol=<symbol>&leverage=<leverage>&leverageEr=<leverageEr>
277
+ 'g-positions/leverage': 5, # ?symbol=<symbol>&leverage=<leverage>&leverageEr=<leverageEr>
278
+ 'g-positions/switch-pos-mode-sync': 5, # ?symbol=<symbol>&targetPosMode=<targetPosMode>
279
+ 'positions/riskLimit': 5, # ?symbol=<symbol>&riskLimit=<riskLimit>&riskLimitEv=<riskLimitEv>
280
+ },
281
+ 'delete': {
282
+ # spot
283
+ 'spot/orders': 2, # ?symbol=<symbol>&orderID=<orderID>
284
+ 'spot/orders/all': 2, # ?symbol=<symbol>&untriggered=<untriggered>
285
+ # 'spot/orders': 5, # ?symbol=<symbol>&clOrdID=<clOrdID>
286
+ # swap
287
+ 'orders/cancel': 1, # ?symbol=<symbol>&orderID=<orderID>
288
+ 'orders': 1, # ?symbol=<symbol>&orderID=<orderID1>,<orderID2>,<orderID3>
289
+ 'orders/all': 3, # ?symbol=<symbol>&untriggered=<untriggered>&text=<text>
290
+ 'g-orders/cancel': 1, # ?symbol=<symbol>&orderID=<orderID>
291
+ 'g-orders': 1, # ?symbol=<symbol>&orderID=<orderID1>,<orderID2>,<orderID3>
292
+ 'g-orders/all': 3, # ?symbol=<symbol>&untriggered=<untriggered>&text=<text>
293
+ },
294
+ },
295
+ },
296
+ 'precisionMode': TICK_SIZE,
297
+ 'fees': {
298
+ 'trading': {
299
+ 'tierBased': False,
300
+ 'percentage': True,
301
+ 'taker': self.parse_number('0.001'),
302
+ 'maker': self.parse_number('0.001'),
303
+ },
304
+ },
305
+ 'requiredCredentials': {
306
+ 'apiKey': True,
307
+ 'secret': True,
308
+ },
309
+ 'exceptions': {
310
+ 'exact': {
311
+ # not documented
312
+ '401': AuthenticationError, # {"code":"401","msg":"401 Failed to load API KEY."}
313
+ '412': BadRequest, # {"code":412,"msg":"Missing parameter - resolution","data":null}
314
+ '6001': BadRequest, # {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
315
+ # documented
316
+ '19999': BadRequest, # REQUEST_IS_DUPLICATED Duplicated request ID
317
+ '10001': DuplicateOrderId, # OM_DUPLICATE_ORDERID Duplicated order ID
318
+ '10002': OrderNotFound, # OM_ORDER_NOT_FOUND Cannot find order ID
319
+ '10003': CancelPending, # OM_ORDER_PENDING_CANCEL Cannot cancel while order is already in pending cancel status
320
+ '10004': CancelPending, # OM_ORDER_PENDING_REPLACE Cannot cancel while order is already in pending cancel status
321
+ '10005': CancelPending, # OM_ORDER_PENDING Cannot cancel while order is already in pending cancel status
322
+ '11001': InsufficientFunds, # TE_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
323
+ '11002': InvalidOrder, # TE_INVALID_RISK_LIMIT Invalid risk limit value
324
+ '11003': InsufficientFunds, # TE_NO_ENOUGH_BALANCE_FOR_NEW_RISK_LIMIT Insufficient available balance
325
+ '11004': InvalidOrder, # TE_INVALID_LEVERAGE invalid input or new leverage is over maximum allowed leverage
326
+ '11005': InsufficientFunds, # TE_NO_ENOUGH_BALANCE_FOR_NEW_LEVERAGE Insufficient available balance
327
+ '11006': ExchangeError, # TE_CANNOT_CHANGE_POSITION_MARGIN_WITHOUT_POSITION Position size is zero. Cannot change margin
328
+ '11007': ExchangeError, # TE_CANNOT_CHANGE_POSITION_MARGIN_FOR_CROSS_MARGIN Cannot change margin under CrossMargin
329
+ '11008': ExchangeError, # TE_CANNOT_REMOVE_POSITION_MARGIN_MORE_THAN_ADDED exceeds the maximum removable Margin
330
+ '11009': ExchangeError, # TE_CANNOT_REMOVE_POSITION_MARGIN_DUE_TO_UNREALIZED_PNL exceeds the maximum removable Margin
331
+ '11010': InsufficientFunds, # TE_CANNOT_ADD_POSITION_MARGIN_DUE_TO_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
332
+ '11011': InvalidOrder, # TE_REDUCE_ONLY_ABORT Cannot accept reduce only order
333
+ '11012': InvalidOrder, # TE_REPLACE_TO_INVALID_QTY Order quantity Error
334
+ '11013': InvalidOrder, # TE_CONDITIONAL_NO_POSITION Position size is zero. Cannot determine conditional order's quantity
335
+ '11014': InvalidOrder, # TE_CONDITIONAL_CLOSE_POSITION_WRONG_SIDE Close position conditional order has the same side
336
+ '11015': InvalidOrder, # TE_CONDITIONAL_TRIGGERED_OR_CANCELED
337
+ '11016': BadRequest, # TE_ADL_NOT_TRADING_REQUESTED_ACCOUNT Request is routed to the wrong trading engine
338
+ '11017': ExchangeError, # TE_ADL_CANNOT_FIND_POSITION Cannot find requested position on current account
339
+ '11018': ExchangeError, # TE_NO_NEED_TO_SETTLE_FUNDING The current account does not need to pay a funding fee
340
+ '11019': ExchangeError, # TE_FUNDING_ALREADY_SETTLED The current account already pays the funding fee
341
+ '11020': ExchangeError, # TE_CANNOT_TRANSFER_OUT_DUE_TO_BONUS Withdraw to wallet needs to remove all remaining bonus. However if bonus is used by position or order cost, withdraw fails.
342
+ '11021': ExchangeError, # TE_INVALID_BONOUS_AMOUNT # Grpc command cannot be negative number Invalid bonus amount
343
+ '11022': AccountSuspended, # TE_REJECT_DUE_TO_BANNED Account is banned
344
+ '11023': ExchangeError, # TE_REJECT_DUE_TO_IN_PROCESS_OF_LIQ Account is in the process of liquidation
345
+ '11024': ExchangeError, # TE_REJECT_DUE_TO_IN_PROCESS_OF_ADL Account is in the process of auto-deleverage
346
+ '11025': BadRequest, # TE_ROUTE_ERROR Request is routed to the wrong trading engine
347
+ '11026': ExchangeError, # TE_UID_ACCOUNT_MISMATCH
348
+ '11027': BadSymbol, # TE_SYMBOL_INVALID Invalid number ID or name
349
+ '11028': BadSymbol, # TE_CURRENCY_INVALID Invalid currency ID or name
350
+ '11029': ExchangeError, # TE_ACTION_INVALID Unrecognized request type
351
+ '11030': ExchangeError, # TE_ACTION_BY_INVALID
352
+ '11031': DDoSProtection, # TE_SO_NUM_EXCEEDS Number of total conditional orders exceeds the max limit
353
+ '11032': DDoSProtection, # TE_AO_NUM_EXCEEDS Number of total active orders exceeds the max limit
354
+ '11033': DuplicateOrderId, # TE_ORDER_ID_DUPLICATE Duplicated order ID
355
+ '11034': InvalidOrder, # TE_SIDE_INVALID Invalid side
356
+ '11035': InvalidOrder, # TE_ORD_TYPE_INVALID Invalid OrderType
357
+ '11036': InvalidOrder, # TE_TIME_IN_FORCE_INVALID Invalid TimeInForce
358
+ '11037': InvalidOrder, # TE_EXEC_INST_INVALID Invalid ExecType
359
+ '11038': InvalidOrder, # TE_TRIGGER_INVALID Invalid trigger type
360
+ '11039': InvalidOrder, # TE_STOP_DIRECTION_INVALID Invalid stop direction type
361
+ '11040': InvalidOrder, # TE_NO_MARK_PRICE Cannot get valid mark price to create conditional order
362
+ '11041': InvalidOrder, # TE_NO_INDEX_PRICE Cannot get valid index price to create conditional order
363
+ '11042': InvalidOrder, # TE_NO_LAST_PRICE Cannot get valid last market price to create conditional order
364
+ '11043': InvalidOrder, # TE_RISING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
365
+ '11044': InvalidOrder, # TE_FALLING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
366
+ '11045': InvalidOrder, # TE_TRIGGER_PRICE_TOO_LARGE Conditional order trigger price is too high
367
+ '11046': InvalidOrder, # TE_TRIGGER_PRICE_TOO_SMALL Conditional order trigger price is too low
368
+ '11047': InvalidOrder, # TE_BUY_TP_SHOULD_GT_BASE TakeProfile BUY conditional order trigger price needs to be greater than reference price
369
+ '11048': InvalidOrder, # TE_BUY_SL_SHOULD_LT_BASE StopLoss BUY condition order price needs to be less than the reference price
370
+ '11049': InvalidOrder, # TE_BUY_SL_SHOULD_GT_LIQ StopLoss BUY condition order price needs to be greater than liquidation price or it will not trigger
371
+ '11050': InvalidOrder, # TE_SELL_TP_SHOULD_LT_BASE TakeProfile SELL conditional order trigger price needs to be less than reference price
372
+ '11051': InvalidOrder, # TE_SELL_SL_SHOULD_LT_LIQ StopLoss SELL condition order price needs to be less than liquidation price or it will not trigger
373
+ '11052': InvalidOrder, # TE_SELL_SL_SHOULD_GT_BASE StopLoss SELL condition order price needs to be greater than the reference price
374
+ '11053': InvalidOrder, # TE_PRICE_TOO_LARGE
375
+ '11054': InvalidOrder, # TE_PRICE_WORSE_THAN_BANKRUPT Order price cannot be more aggressive than bankrupt price if self order has instruction to close a position
376
+ '11055': InvalidOrder, # TE_PRICE_TOO_SMALL Order price is too low
377
+ '11056': InvalidOrder, # TE_QTY_TOO_LARGE Order quantity is too large
378
+ '11057': InvalidOrder, # TE_QTY_NOT_MATCH_REDUCE_ONLY Does not allow ReduceOnly order without position
379
+ '11058': InvalidOrder, # TE_QTY_TOO_SMALL Order quantity is too small
380
+ '11059': InvalidOrder, # TE_TP_SL_QTY_NOT_MATCH_POS Position size is zero. Cannot accept any TakeProfit or StopLoss order
381
+ '11060': InvalidOrder, # TE_SIDE_NOT_CLOSE_POS TakeProfit or StopLoss order has wrong side. Cannot close position
382
+ '11061': CancelPending, # TE_ORD_ALREADY_PENDING_CANCEL Repeated cancel request
383
+ '11062': InvalidOrder, # TE_ORD_ALREADY_CANCELED Order is already canceled
384
+ '11063': InvalidOrder, # TE_ORD_STATUS_CANNOT_CANCEL Order is not able to be canceled under current status
385
+ '11064': InvalidOrder, # TE_ORD_ALREADY_PENDING_REPLACE Replace request is rejected because order is already in pending replace status
386
+ '11065': InvalidOrder, # TE_ORD_REPLACE_NOT_MODIFIED Replace request does not modify any parameters of the order
387
+ '11066': InvalidOrder, # TE_ORD_STATUS_CANNOT_REPLACE Order is not able to be replaced under current status
388
+ '11067': InvalidOrder, # TE_CANNOT_REPLACE_PRICE Market conditional order cannot change price
389
+ '11068': InvalidOrder, # TE_CANNOT_REPLACE_QTY Condtional order for closing position cannot change order quantity, since the order quantity is determined by position size already
390
+ '11069': ExchangeError, # TE_ACCOUNT_NOT_IN_RANGE The account ID in the request is not valid or is not in the range of the current process
391
+ '11070': BadSymbol, # TE_SYMBOL_NOT_IN_RANGE The symbol is invalid
392
+ '11071': InvalidOrder, # TE_ORD_STATUS_CANNOT_TRIGGER
393
+ '11072': InvalidOrder, # TE_TKFR_NOT_IN_RANGE The fee value is not valid
394
+ '11073': InvalidOrder, # TE_MKFR_NOT_IN_RANGE The fee value is not valid
395
+ '11074': InvalidOrder, # TE_CANNOT_ATTACH_TP_SL Order request cannot contain TP/SL parameters when the account already has positions
396
+ '11075': InvalidOrder, # TE_TP_TOO_LARGE TakeProfit price is too large
397
+ '11076': InvalidOrder, # TE_TP_TOO_SMALL TakeProfit price is too small
398
+ '11077': InvalidOrder, # TE_TP_TRIGGER_INVALID Invalid trigger type
399
+ '11078': InvalidOrder, # TE_SL_TOO_LARGE StopLoss price is too large
400
+ '11079': InvalidOrder, # TE_SL_TOO_SMALL StopLoss price is too small
401
+ '11080': InvalidOrder, # TE_SL_TRIGGER_INVALID Invalid trigger type
402
+ '11081': InvalidOrder, # TE_RISK_LIMIT_EXCEEDS Total potential position breaches current risk limit
403
+ '11082': InsufficientFunds, # TE_CANNOT_COVER_ESTIMATE_ORDER_LOSS The remaining balance cannot cover the potential unrealized PnL for self new order
404
+ '11083': InvalidOrder, # TE_TAKE_PROFIT_ORDER_DUPLICATED TakeProfit order already exists
405
+ '11084': InvalidOrder, # TE_STOP_LOSS_ORDER_DUPLICATED StopLoss order already exists
406
+ '11085': DuplicateOrderId, # TE_CL_ORD_ID_DUPLICATE ClOrdId is duplicated
407
+ '11086': InvalidOrder, # TE_PEG_PRICE_TYPE_INVALID PegPriceType is invalid
408
+ '11087': InvalidOrder, # TE_BUY_TS_SHOULD_LT_BASE The trailing order's StopPrice should be less than the current last price
409
+ '11088': InvalidOrder, # TE_BUY_TS_SHOULD_GT_LIQ The traling order's StopPrice should be greater than the current liquidation price
410
+ '11089': InvalidOrder, # TE_SELL_TS_SHOULD_LT_LIQ The traling order's StopPrice should be greater than the current last price
411
+ '11090': InvalidOrder, # TE_SELL_TS_SHOULD_GT_BASE The traling order's StopPrice should be less than the current liquidation price
412
+ '11091': InvalidOrder, # TE_BUY_REVERT_VALUE_SHOULD_LT_ZERO The PegOffset should be less than zero
413
+ '11092': InvalidOrder, # TE_SELL_REVERT_VALUE_SHOULD_GT_ZERO The PegOffset should be greater than zero
414
+ '11093': InvalidOrder, # TE_BUY_TTP_SHOULD_ACTIVATE_ABOVE_BASE The activation price should be greater than the current last price
415
+ '11094': InvalidOrder, # TE_SELL_TTP_SHOULD_ACTIVATE_BELOW_BASE The activation price should be less than the current last price
416
+ '11095': InvalidOrder, # TE_TRAILING_ORDER_DUPLICATED A trailing order exists already
417
+ '11096': InvalidOrder, # TE_CLOSE_ORDER_CANNOT_ATTACH_TP_SL An order to close position cannot have trailing instruction
418
+ '11097': BadRequest, # TE_CANNOT_FIND_WALLET_OF_THIS_CURRENCY This crypto is not supported
419
+ '11098': BadRequest, # TE_WALLET_INVALID_ACTION Invalid action on wallet
420
+ '11099': ExchangeError, # TE_WALLET_VID_UNMATCHED Wallet operation request has a wrong wallet vid
421
+ '11100': InsufficientFunds, # TE_WALLET_INSUFFICIENT_BALANCE Wallet has insufficient balance
422
+ '11101': InsufficientFunds, # TE_WALLET_INSUFFICIENT_LOCKED_BALANCE Locked balance in wallet is not enough for unlock/withdraw request
423
+ '11102': BadRequest, # TE_WALLET_INVALID_DEPOSIT_AMOUNT Deposit amount must be greater than zero
424
+ '11103': BadRequest, # TE_WALLET_INVALID_WITHDRAW_AMOUNT Withdraw amount must be less than zero
425
+ '11104': BadRequest, # TE_WALLET_REACHED_MAX_AMOUNT Deposit makes wallet exceed max amount allowed
426
+ '11105': InsufficientFunds, # TE_PLACE_ORDER_INSUFFICIENT_BASE_BALANCE Insufficient funds in base wallet
427
+ '11106': InsufficientFunds, # TE_PLACE_ORDER_INSUFFICIENT_QUOTE_BALANCE Insufficient funds in quote wallet
428
+ '11107': ExchangeError, # TE_CANNOT_CONNECT_TO_REQUEST_SEQ TradingEngine failed to connect with CrossEngine
429
+ '11108': InvalidOrder, # TE_CANNOT_REPLACE_OR_CANCEL_MARKET_ORDER Cannot replace/amend market order
430
+ '11109': InvalidOrder, # TE_CANNOT_REPLACE_OR_CANCEL_IOC_ORDER Cannot replace/amend ImmediateOrCancel order
431
+ '11110': InvalidOrder, # TE_CANNOT_REPLACE_OR_CANCEL_FOK_ORDER Cannot replace/amend FillOrKill order
432
+ '11111': InvalidOrder, # TE_MISSING_ORDER_ID OrderId is missing
433
+ '11112': InvalidOrder, # TE_QTY_TYPE_INVALID QtyType is invalid
434
+ '11113': BadRequest, # TE_USER_ID_INVALID UserId is invalid
435
+ '11114': InvalidOrder, # TE_ORDER_VALUE_TOO_LARGE Order value is too large
436
+ '11115': InvalidOrder, # TE_ORDER_VALUE_TOO_SMALL Order value is too small
437
+ '11116': InvalidOrder, # TE_BO_NUM_EXCEEDS Details: the total count of brakcet orders should equal or less than 5
438
+ '11117': InvalidOrder, # TE_BO_CANNOT_HAVE_BO_WITH_DIFF_SIDE Details: all bracket orders should have the same Side.
439
+ '11118': InvalidOrder, # TE_BO_TP_PRICE_INVALID Details: bracker order take profit price is invalid
440
+ '11119': InvalidOrder, # TE_BO_SL_PRICE_INVALID Details: bracker order stop loss price is invalid
441
+ '11120': InvalidOrder, # TE_BO_SL_TRIGGER_PRICE_INVALID Details: bracker order stop loss trigger price is invalid
442
+ '11121': InvalidOrder, # TE_BO_CANNOT_REPLACE Details: cannot replace bracket order.
443
+ '11122': InvalidOrder, # TE_BO_BOTP_STATUS_INVALID Details: bracket take profit order status is invalid
444
+ '11123': InvalidOrder, # TE_BO_CANNOT_PLACE_BOTP_OR_BOSL_ORDER Details: cannot place bracket take profit order
445
+ '11124': InvalidOrder, # TE_BO_CANNOT_REPLACE_BOTP_OR_BOSL_ORDER Details: cannot place bracket stop loss order
446
+ '11125': InvalidOrder, # TE_BO_CANNOT_CANCEL_BOTP_OR_BOSL_ORDER Details: cannot cancel bracket sl/tp order
447
+ '11126': InvalidOrder, # TE_BO_DONOT_SUPPORT_API Details: doesn't support bracket order via API
448
+ '11128': InvalidOrder, # TE_BO_INVALID_EXECINST Details: ExecInst value is invalid
449
+ '11129': InvalidOrder, # TE_BO_MUST_BE_SAME_SIDE_AS_POS Details: bracket order should have the same side's side
450
+ '11130': InvalidOrder, # TE_BO_WRONG_SL_TRIGGER_TYPE Details: bracket stop loss order trigger type is invalid
451
+ '11131': InvalidOrder, # TE_BO_WRONG_TP_TRIGGER_TYPE Details: bracket take profit order trigger type is invalid
452
+ '11132': InvalidOrder, # TE_BO_ABORT_BOSL_DUE_BOTP_CREATE_FAILED Details: cancel bracket stop loss order due failed to create take profit order.
453
+ '11133': InvalidOrder, # TE_BO_ABORT_BOSL_DUE_BOPO_CANCELED Details: cancel bracket stop loss order due main order canceled.
454
+ '11134': InvalidOrder, # TE_BO_ABORT_BOTP_DUE_BOPO_CANCELED Details: cancel bracket take profit order due main order canceled.
455
+ # not documented
456
+ '30000': BadRequest, # {"code":30000,"msg":"Please double check input arguments","data":null}
457
+ '30018': BadRequest, # {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
458
+ '34003': PermissionDenied, # {"code":34003,"msg":"Access forbidden","data":null}
459
+ '35104': InsufficientFunds, # {"code":35104,"msg":"phemex.spot.wallet.balance.notenough","data":null}
460
+ '39995': RateLimitExceeded, # {"code": "39995","msg": "Too many requests."}
461
+ '39996': PermissionDenied, # {"code": "39996","msg": "Access denied."}
462
+ '39997': BadSymbol, # {"code":39997,"msg":"Symbol not listed sMOVRUSDT","data":null}
463
+ },
464
+ 'broad': {
465
+ '401 Insufficient privilege': PermissionDenied, # {"code": "401","msg": "401 Insufficient privilege."}
466
+ '401 Request IP mismatch': PermissionDenied, # {"code": "401","msg": "401 Request IP mismatch."}
467
+ 'Failed to find api-key': AuthenticationError, # {"msg":"Failed to find api-key 1c5ec63fd-660d-43ea-847a-0d3ba69e106e","code":10500}
468
+ 'Missing required parameter': BadRequest, # {"msg":"Missing required parameter","code":10500}
469
+ 'API Signature verification failed': AuthenticationError, # {"msg":"API Signature verification failed.","code":10500}
470
+ 'Api key not found': AuthenticationError, # {"msg":"Api key not found 698dc9e3-6faa-4910-9476-12857e79e198","code":"10500"}
471
+ },
472
+ },
473
+ 'options': {
474
+ 'brokerId': 'CCXT123456', # updated from CCXT to CCXT123456
475
+ 'x-phemex-request-expiry': 60, # in seconds
476
+ 'createOrderByQuoteRequiresPrice': True,
477
+ 'networks': {
478
+ 'TRC20': 'TRX',
479
+ 'ERC20': 'ETH',
480
+ 'BEP20': 'BNB',
481
+ },
482
+ 'defaultNetworks': {
483
+ 'USDT': 'ETH',
484
+ },
485
+ 'defaultSubType': 'linear',
486
+ 'accountsByType': {
487
+ 'spot': 'spot',
488
+ 'swap': 'future',
489
+ },
490
+ 'stableCoins': [
491
+ 'BUSD',
492
+ 'FEI',
493
+ 'TUSD',
494
+ 'USD',
495
+ 'USDC',
496
+ 'USDD',
497
+ 'USDP',
498
+ 'USDT',
499
+ ],
500
+ 'transfer': {
501
+ 'fillResponseFromRequest': True,
502
+ },
503
+ },
504
+ })
505
+
506
+ def parse_safe_number(self, value=None):
507
+ if value is None:
508
+ return value
509
+ parts = value.split(',')
510
+ value = ''.join(parts)
511
+ parts = value.split(' ')
512
+ return self.safe_number(parts, 0)
513
+
514
+ def parse_swap_market(self, market: dict):
515
+ #
516
+ # {
517
+ # "symbol":"BTCUSD",
518
+ # "code":"1",
519
+ # "type":"Perpetual",
520
+ # "displaySymbol":"BTC / USD",
521
+ # "indexSymbol":".BTC",
522
+ # "markSymbol":".MBTC",
523
+ # "fundingRateSymbol":".BTCFR",
524
+ # "fundingRate8hSymbol":".BTCFR8H",
525
+ # "contractUnderlyingAssets":"USD",
526
+ # "settleCurrency":"BTC",
527
+ # "quoteCurrency":"USD",
528
+ # "contractSize":"1 USD",
529
+ # "lotSize":1,
530
+ # "tickSize":0.5,
531
+ # "priceScale":4,
532
+ # "ratioScale":8,
533
+ # "pricePrecision":1,
534
+ # "minPriceEp":5000,
535
+ # "maxPriceEp":10000000000,
536
+ # "maxOrderQty":1000000,
537
+ # "status":"Listed",
538
+ # "tipOrderQty":1000000,
539
+ # "listTime":"1574650800000",
540
+ # "majorSymbol":true,
541
+ # "steps":"50",
542
+ # "riskLimits":[
543
+ # {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
544
+ # {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
545
+ # {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
546
+ # ],
547
+ # "underlyingSymbol":".BTC",
548
+ # "baseCurrency":"BTC",
549
+ # "settlementCurrency":"BTC",
550
+ # "valueScale":8,
551
+ # "defaultLeverage":0,
552
+ # "maxLeverage":100,
553
+ # "initMarginEr":"1000000",
554
+ # "maintMarginEr":"500000",
555
+ # "defaultRiskLimitEv":10000000000,
556
+ # "deleverage":true,
557
+ # "makerFeeRateEr":-250000,
558
+ # "takerFeeRateEr":750000,
559
+ # "fundingInterval":8,
560
+ # "marketUrl":"https://phemex.com/trade/BTCUSD",
561
+ # "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.",
562
+ # }
563
+ #
564
+ id = self.safe_string(market, 'symbol')
565
+ baseId = self.safe_string_2(market, 'baseCurrency', 'contractUnderlyingAssets')
566
+ quoteId = self.safe_string(market, 'quoteCurrency')
567
+ settleId = self.safe_string(market, 'settleCurrency')
568
+ base = self.safe_currency_code(baseId)
569
+ quote = self.safe_currency_code(quoteId)
570
+ settle = self.safe_currency_code(settleId)
571
+ inverse = False
572
+ if settleId != quoteId:
573
+ inverse = True
574
+ priceScale = self.safe_integer(market, 'priceScale')
575
+ ratioScale = self.safe_integer(market, 'ratioScale')
576
+ valueScale = self.safe_integer(market, 'valueScale')
577
+ minPriceEp = self.safe_string(market, 'minPriceEp')
578
+ maxPriceEp = self.safe_string(market, 'maxPriceEp')
579
+ makerFeeRateEr = self.safe_string(market, 'makerFeeRateEr')
580
+ takerFeeRateEr = self.safe_string(market, 'takerFeeRateEr')
581
+ status = self.safe_string(market, 'status')
582
+ contractSizeString = self.safe_string(market, 'contractSize', ' ')
583
+ contractSize: Num = None
584
+ if settle == 'USDT':
585
+ contractSize = self.parse_number('1')
586
+ elif contractSizeString.find(' '):
587
+ # "1 USD"
588
+ # "0.005 ETH"
589
+ parts = contractSizeString.split(' ')
590
+ contractSize = self.parse_number(parts[0])
591
+ else:
592
+ # "1.0"
593
+ contractSize = self.parse_number(contractSizeString)
594
+ return self.safe_market_structure({
595
+ 'id': id,
596
+ 'symbol': base + '/' + quote + ':' + settle,
597
+ 'base': base,
598
+ 'quote': quote,
599
+ 'settle': settle,
600
+ 'baseId': baseId,
601
+ 'quoteId': quoteId,
602
+ 'settleId': settleId,
603
+ 'type': 'swap',
604
+ 'spot': False,
605
+ 'margin': False,
606
+ 'swap': True,
607
+ 'future': False,
608
+ 'option': False,
609
+ 'active': status == 'Listed',
610
+ 'contract': True,
611
+ 'linear': not inverse,
612
+ 'inverse': inverse,
613
+ 'taker': self.parse_number(self.from_en(takerFeeRateEr, ratioScale)),
614
+ 'maker': self.parse_number(self.from_en(makerFeeRateEr, ratioScale)),
615
+ 'contractSize': contractSize,
616
+ 'expiry': None,
617
+ 'expiryDatetime': None,
618
+ 'strike': None,
619
+ 'optionType': None,
620
+ 'priceScale': priceScale,
621
+ 'valueScale': valueScale,
622
+ 'ratioScale': ratioScale,
623
+ 'precision': {
624
+ 'amount': self.safe_number_2(market, 'lotSize', 'qtyStepSize'),
625
+ 'price': self.safe_number(market, 'tickSize'),
626
+ },
627
+ 'limits': {
628
+ 'leverage': {
629
+ 'min': self.parse_number('1'),
630
+ 'max': self.safe_number(market, 'maxLeverage'),
631
+ },
632
+ 'amount': {
633
+ 'min': None,
634
+ 'max': None,
635
+ },
636
+ 'price': {
637
+ 'min': self.parse_number(self.from_en(minPriceEp, priceScale)),
638
+ 'max': self.parse_number(self.from_en(maxPriceEp, priceScale)),
639
+ },
640
+ 'cost': {
641
+ 'min': None,
642
+ 'max': self.parse_number(self.safe_string(market, 'maxOrderQty')),
643
+ },
644
+ },
645
+ 'created': None,
646
+ 'info': market,
647
+ })
648
+
649
+ def parse_spot_market(self, market: dict):
650
+ #
651
+ # {
652
+ # "symbol":"sBTCUSDT",
653
+ # "code":1001,
654
+ # "type":"Spot",
655
+ # "displaySymbol":"BTC / USDT",
656
+ # "quoteCurrency":"USDT",
657
+ # "priceScale":8,
658
+ # "ratioScale":8,
659
+ # "pricePrecision":2,
660
+ # "baseCurrency":"BTC",
661
+ # "baseTickSize":"0.000001 BTC",
662
+ # "baseTickSizeEv":100,
663
+ # "quoteTickSize":"0.01 USDT",
664
+ # "quoteTickSizeEv":1000000,
665
+ # "baseQtyPrecision":6,
666
+ # "quoteQtyPrecision":2,
667
+ # "minOrderValue":"10 USDT",
668
+ # "minOrderValueEv":1000000000,
669
+ # "maxBaseOrderSize":"1000 BTC",
670
+ # "maxBaseOrderSizeEv":100000000000,
671
+ # "maxOrderValue":"5,000,000 USDT",
672
+ # "maxOrderValueEv":500000000000000,
673
+ # "defaultTakerFee":"0.001",
674
+ # "defaultTakerFeeEr":100000,
675
+ # "defaultMakerFee":"0.001",
676
+ # "defaultMakerFeeEr":100000,
677
+ # "description":"BTCUSDT is a BTC/USDT spot trading pair. Minimum order value is 1 USDT",
678
+ # "status":"Listed",
679
+ # "tipOrderQty":2,
680
+ # "listTime":1589338800000,
681
+ # "buyPriceUpperLimitPct":110,
682
+ # "sellPriceLowerLimitPct":90,
683
+ # "leverage":5
684
+ # },
685
+ #
686
+ type = self.safe_string_lower(market, 'type')
687
+ id = self.safe_string(market, 'symbol')
688
+ quoteId = self.safe_string(market, 'quoteCurrency')
689
+ baseId = self.safe_string(market, 'baseCurrency')
690
+ base = self.safe_currency_code(baseId)
691
+ quote = self.safe_currency_code(quoteId)
692
+ status = self.safe_string(market, 'status')
693
+ precisionAmount = self.parse_safe_number(self.safe_string(market, 'baseTickSize'))
694
+ precisionPrice = self.parse_safe_number(self.safe_string(market, 'quoteTickSize'))
695
+ return self.safe_market_structure({
696
+ 'id': id,
697
+ 'symbol': base + '/' + quote,
698
+ 'base': base,
699
+ 'quote': quote,
700
+ 'settle': None,
701
+ 'baseId': baseId,
702
+ 'quoteId': quoteId,
703
+ 'settleId': None,
704
+ 'type': type,
705
+ 'spot': True,
706
+ 'margin': False,
707
+ 'swap': False,
708
+ 'future': False,
709
+ 'option': False,
710
+ 'active': status == 'Listed',
711
+ 'contract': False,
712
+ 'linear': None,
713
+ 'inverse': None,
714
+ 'taker': self.safe_number(market, 'defaultTakerFee'),
715
+ 'maker': self.safe_number(market, 'defaultMakerFee'),
716
+ 'contractSize': None,
717
+ 'expiry': None,
718
+ 'expiryDatetime': None,
719
+ 'strike': None,
720
+ 'optionType': None,
721
+ 'priceScale': self.safe_integer(market, 'priceScale'),
722
+ 'valueScale': self.safe_integer(market, 'valueScale'),
723
+ 'ratioScale': self.safe_integer(market, 'ratioScale'),
724
+ 'precision': {
725
+ 'amount': precisionAmount,
726
+ 'price': precisionPrice,
727
+ },
728
+ 'limits': {
729
+ 'leverage': {
730
+ 'min': None,
731
+ 'max': None,
732
+ },
733
+ 'amount': {
734
+ 'min': precisionAmount,
735
+ 'max': self.parse_safe_number(self.safe_string(market, 'maxBaseOrderSize')),
736
+ },
737
+ 'price': {
738
+ 'min': precisionPrice,
739
+ 'max': None,
740
+ },
741
+ 'cost': {
742
+ 'min': self.parse_safe_number(self.safe_string(market, 'minOrderValue')),
743
+ 'max': self.parse_safe_number(self.safe_string(market, 'maxOrderValue')),
744
+ },
745
+ },
746
+ 'created': None,
747
+ 'info': market,
748
+ })
749
+
750
+ async def fetch_markets(self, params={}) -> List[Market]:
751
+ """
752
+ retrieves data on all markets for phemex
753
+ :param dict [params]: extra parameters specific to the exchange API endpoint
754
+ :returns dict[]: an array of objects representing market data
755
+ """
756
+ v2Products = await self.v2GetPublicProducts(params)
757
+ #
758
+ # {
759
+ # "code":0,
760
+ # "msg":"",
761
+ # "data":{
762
+ # "currencies":[
763
+ # {"currency":"BTC","name":"Bitcoin","code":1,"valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"BTC","inAssetsDisplay":1,"perpetual":0,"stableCoin":0,"assetsPrecision":8},
764
+ # {"currency":"USD","name":"USD","code":2,"valueScale":4,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"USD","inAssetsDisplay":1,"perpetual":0,"stableCoin":0,"assetsPrecision":2},
765
+ # {"currency":"USDT","name":"TetherUS","code":3,"valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"USDT","inAssetsDisplay":1,"perpetual":2,"stableCoin":1,"assetsPrecision":8},
766
+ # ],
767
+ # "products":[
768
+ # {
769
+ # "symbol":"BTCUSD",
770
+ # "code":1,
771
+ # "type":"Perpetual"
772
+ # "displaySymbol":"BTC / USD",
773
+ # "indexSymbol":".BTC",
774
+ # "markSymbol":".MBTC",
775
+ # "fundingRateSymbol":".BTCFR",
776
+ # "fundingRate8hSymbol":".BTCFR8H",
777
+ # "contractUnderlyingAssets":"USD",
778
+ # "settleCurrency":"BTC",
779
+ # "quoteCurrency":"USD",
780
+ # "contractSize":1.0,
781
+ # "lotSize":1,
782
+ # "tickSize":0.5,
783
+ # "priceScale":4,
784
+ # "ratioScale":8,
785
+ # "pricePrecision":1,
786
+ # "minPriceEp":5000,
787
+ # "maxPriceEp":10000000000,
788
+ # "maxOrderQty":1000000,
789
+ # "description":"BTC/USD perpetual contracts are priced on the .BTC Index. Each contract is worth 1 USD. Funding fees are paid and received every 8 hours at UTC time: 00:00, 08:00 and 16:00.",
790
+ # "status":"Listed",
791
+ # "tipOrderQty":1000000,
792
+ # "listTime":1574650800000,
793
+ # "majorSymbol":true,
794
+ # "defaultLeverage":"-10",
795
+ # "fundingInterval":28800,
796
+ # "maxLeverage":100
797
+ # },
798
+ # {
799
+ # "symbol":"sBTCUSDT",
800
+ # "code":1001,
801
+ # "type":"Spot",
802
+ # "displaySymbol":"BTC / USDT",
803
+ # "quoteCurrency":"USDT",
804
+ # "priceScale":8,
805
+ # "ratioScale":8,
806
+ # "pricePrecision":2,
807
+ # "baseCurrency":"BTC",
808
+ # "baseTickSize":"0.000001 BTC",
809
+ # "baseTickSizeEv":100,
810
+ # "quoteTickSize":"0.01 USDT",
811
+ # "quoteTickSizeEv":1000000,
812
+ # "baseQtyPrecision":6,
813
+ # "quoteQtyPrecision":2,
814
+ # "minOrderValue":"10 USDT",
815
+ # "minOrderValueEv":1000000000,
816
+ # "maxBaseOrderSize":"1000 BTC",
817
+ # "maxBaseOrderSizeEv":100000000000,
818
+ # "maxOrderValue":"5,000,000 USDT",
819
+ # "maxOrderValueEv":500000000000000,
820
+ # "defaultTakerFee":"0.001",
821
+ # "defaultTakerFeeEr":100000,
822
+ # "defaultMakerFee":"0.001",
823
+ # "defaultMakerFeeEr":100000,
824
+ # "description":"BTCUSDT is a BTC/USDT spot trading pair. Minimum order value is 1 USDT",
825
+ # "status":"Listed",
826
+ # "tipOrderQty":2,
827
+ # "listTime":1589338800000,
828
+ # "buyPriceUpperLimitPct":110,
829
+ # "sellPriceLowerLimitPct":90,
830
+ # "leverage":5
831
+ # },
832
+ # ],
833
+ # "perpProductsV2":[
834
+ # {
835
+ # "symbol":"BTCUSDT",
836
+ # "code":41541,
837
+ # "type":"PerpetualV2",
838
+ # "displaySymbol":"BTC / USDT",
839
+ # "indexSymbol":".BTCUSDT",
840
+ # "markSymbol":".MBTCUSDT",
841
+ # "fundingRateSymbol":".BTCUSDTFR",
842
+ # "fundingRate8hSymbol":".BTCUSDTFR8H",
843
+ # "contractUnderlyingAssets":"BTC",
844
+ # "settleCurrency":"USDT",
845
+ # "quoteCurrency":"USDT",
846
+ # "tickSize":"0.1",
847
+ # "priceScale":0,
848
+ # "ratioScale":0,
849
+ # "pricePrecision":1,
850
+ # "baseCurrency":"BTC",
851
+ # "description":"BTC/USDT perpetual contracts are priced on the .BTCUSDT Index. Each contract is worth 1 BTC. Funding fees are paid and received every 8 hours at UTC time: 00:00, 08:00 and 16:00.",
852
+ # "status":"Listed",
853
+ # "tipOrderQty":0,
854
+ # "listTime":1668225600000,
855
+ # "majorSymbol":true,
856
+ # "defaultLeverage":"-10",
857
+ # "fundingInterval":28800,
858
+ # "maxLeverage":100,
859
+ # "maxOrderQtyRq":"1000",
860
+ # "maxPriceRp":"2000000000",
861
+ # "minOrderValueRv":"1",
862
+ # "minPriceRp":"1000.0",
863
+ # "qtyPrecision":3,
864
+ # "qtyStepSize":"0.001",
865
+ # "tipOrderQtyRq":"200",
866
+ # "maxOpenPosLeverage":100.0
867
+ # },
868
+ # ],
869
+ # "riskLimits":[
870
+ # {
871
+ # "symbol":"BTCUSD",
872
+ # "steps":"50",
873
+ # "riskLimits":[
874
+ # {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
875
+ # {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
876
+ # {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
877
+ # ]
878
+ # },
879
+ # ],
880
+ # "leverages":[
881
+ # {"initialMargin":"1.0%","initialMarginEr":1000000,"options":[1,2,3,5,10,25,50,100]},
882
+ # {"initialMargin":"1.5%","initialMarginEr":1500000,"options":[1,2,3,5,10,25,50,66]},
883
+ # {"initialMargin":"2.0%","initialMarginEr":2000000,"options":[1,2,3,5,10,25,33,50]},
884
+ # ],
885
+ # "riskLimitsV2":[
886
+ # {
887
+ # "symbol":"BTCUSDT",
888
+ # "steps":"2000K",
889
+ # "riskLimits":[
890
+ # {"limit":2000000,"initialMarginRr":"0.01","maintenanceMarginRr":"0.005"},,
891
+ # {"limit":4000000,"initialMarginRr":"0.015","maintenanceMarginRr":"0.0075"},
892
+ # {"limit":6000000,"initialMarginRr":"0.02","maintenanceMarginRr":"0.01"},
893
+ # ]
894
+ # },
895
+ # ],
896
+ # "leveragesV2":[
897
+ # {"options":[1.0,2.0,3.0,5.0,10.0,25.0,50.0,100.0],"initialMarginRr":"0.01"},
898
+ # {"options":[1.0,2.0,3.0,5.0,10.0,25.0,50.0,66.67],"initialMarginRr":"0.015"},
899
+ # {"options":[1.0,2.0,3.0,5.0,10.0,25.0,33.0,50.0],"initialMarginRr":"0.02"},
900
+ # ],
901
+ # "ratioScale":8,
902
+ # "md5Checksum":"5c6604814d3c1bafbe602c3d11a7e8bf",
903
+ # }
904
+ # }
905
+ #
906
+ v1Products = await self.v1GetExchangePublicProducts(params)
907
+ v1ProductsData = self.safe_value(v1Products, 'data', [])
908
+ #
909
+ # {
910
+ # "code":0,
911
+ # "msg":"OK",
912
+ # "data":[
913
+ # {
914
+ # "symbol":"BTCUSD",
915
+ # "underlyingSymbol":".BTC",
916
+ # "quoteCurrency":"USD",
917
+ # "baseCurrency":"BTC",
918
+ # "settlementCurrency":"BTC",
919
+ # "maxOrderQty":1000000,
920
+ # "maxPriceEp":100000000000000,
921
+ # "lotSize":1,
922
+ # "tickSize":"0.5",
923
+ # "contractSize":"1 USD",
924
+ # "priceScale":4,
925
+ # "ratioScale":8,
926
+ # "valueScale":8,
927
+ # "defaultLeverage":0,
928
+ # "maxLeverage":100,
929
+ # "initMarginEr":"1000000",
930
+ # "maintMarginEr":"500000",
931
+ # "defaultRiskLimitEv":10000000000,
932
+ # "deleverage":true,
933
+ # "makerFeeRateEr":-250000,
934
+ # "takerFeeRateEr":750000,
935
+ # "fundingInterval":8,
936
+ # "marketUrl":"https://phemex.com/trade/BTCUSD",
937
+ # "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.",
938
+ # "type":"Perpetual"
939
+ # },
940
+ # ]
941
+ # }
942
+ #
943
+ v2ProductsData = self.safe_value(v2Products, 'data', {})
944
+ products = self.safe_value(v2ProductsData, 'products', [])
945
+ perpetualProductsV2 = self.safe_value(v2ProductsData, 'perpProductsV2', [])
946
+ products = self.array_concat(products, perpetualProductsV2)
947
+ riskLimits = self.safe_value(v2ProductsData, 'riskLimits', [])
948
+ riskLimitsV2 = self.safe_value(v2ProductsData, 'riskLimitsV2', [])
949
+ riskLimits = self.array_concat(riskLimits, riskLimitsV2)
950
+ currencies = self.safe_value(v2ProductsData, 'currencies', [])
951
+ riskLimitsById = self.index_by(riskLimits, 'symbol')
952
+ v1ProductsById = self.index_by(v1ProductsData, 'symbol')
953
+ currenciesByCode = self.index_by(currencies, 'currency')
954
+ result = []
955
+ for i in range(0, len(products)):
956
+ market = products[i]
957
+ type = self.safe_string_lower(market, 'type')
958
+ if (type == 'perpetual') or (type == 'perpetualv2'):
959
+ id = self.safe_string(market, 'symbol')
960
+ riskLimitValues = self.safe_value(riskLimitsById, id, {})
961
+ market = self.extend(market, riskLimitValues)
962
+ v1ProductsValues = self.safe_value(v1ProductsById, id, {})
963
+ market = self.extend(market, v1ProductsValues)
964
+ market = self.parse_swap_market(market)
965
+ else:
966
+ baseCurrency = self.safe_string(market, 'baseCurrency')
967
+ currencyValues = self.safe_value(currenciesByCode, baseCurrency, {})
968
+ valueScale = self.safe_string(currencyValues, 'valueScale', '8')
969
+ market = self.extend(market, {'valueScale': valueScale})
970
+ market = self.parse_spot_market(market)
971
+ result.append(market)
972
+ return result
973
+
974
+ async def fetch_currencies(self, params={}) -> Currencies:
975
+ """
976
+ fetches all available currencies on an exchange
977
+ :param dict [params]: extra parameters specific to the exchange API endpoint
978
+ :returns dict: an associative dictionary of currencies
979
+ """
980
+ response = await self.v2GetPublicProducts(params)
981
+ #
982
+ # {
983
+ # "code":0,
984
+ # "msg":"OK",
985
+ # "data":{
986
+ # ...,
987
+ # "currencies":[
988
+ # {"currency":"BTC","name":"Bitcoin","code":1,"valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"BTC","inAssetsDisplay":1,"perpetual":0,"stableCoin":0,"assetsPrecision":8},
989
+ # {"currency":"USD","name":"USD","code":2,"valueScale":4,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"USD","inAssetsDisplay":1,"perpetual":0,"stableCoin":0,"assetsPrecision":2},
990
+ # {"currency":"USDT","name":"TetherUS","code":3,"valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"needAddrTag":0,"status":"Listed","displayCurrency":"USDT","inAssetsDisplay":1,"perpetual":2,"stableCoin":1,"assetsPrecision":8},
991
+ # ],
992
+ # ...
993
+ # }
994
+ # }
995
+ data = self.safe_value(response, 'data', {})
996
+ currencies = self.safe_value(data, 'currencies', [])
997
+ result: dict = {}
998
+ for i in range(0, len(currencies)):
999
+ currency = currencies[i]
1000
+ id = self.safe_string(currency, 'currency')
1001
+ name = self.safe_string(currency, 'name')
1002
+ code = self.safe_currency_code(id)
1003
+ status = self.safe_string(currency, 'status')
1004
+ valueScaleString = self.safe_string(currency, 'valueScale')
1005
+ valueScale = int(valueScaleString)
1006
+ minValueEv = self.safe_string(currency, 'minValueEv')
1007
+ maxValueEv = self.safe_string(currency, 'maxValueEv')
1008
+ minAmount: Num = None
1009
+ maxAmount: Num = None
1010
+ precision: Num = None
1011
+ if valueScale is not None:
1012
+ precisionString = self.parse_precision(valueScaleString)
1013
+ precision = self.parse_number(precisionString)
1014
+ minAmount = self.parse_number(Precise.string_mul(minValueEv, precisionString))
1015
+ maxAmount = self.parse_number(Precise.string_mul(maxValueEv, precisionString))
1016
+ result[code] = {
1017
+ 'id': id,
1018
+ 'info': currency,
1019
+ 'code': code,
1020
+ 'name': name,
1021
+ 'active': status == 'Listed',
1022
+ 'deposit': None,
1023
+ 'withdraw': None,
1024
+ 'fee': None,
1025
+ 'precision': precision,
1026
+ 'limits': {
1027
+ 'amount': {
1028
+ 'min': minAmount,
1029
+ 'max': maxAmount,
1030
+ },
1031
+ 'withdraw': {
1032
+ 'min': None,
1033
+ 'max': None,
1034
+ },
1035
+ },
1036
+ 'valueScale': valueScale,
1037
+ 'networks': {},
1038
+ }
1039
+ return result
1040
+
1041
+ def custom_parse_bid_ask(self, bidask, priceKey=0, amountKey=1, market: Market = None):
1042
+ if market is None:
1043
+ raise ArgumentsRequired(self.id + ' customParseBidAsk() requires a market argument')
1044
+ amount = self.safe_string(bidask, amountKey)
1045
+ if market['spot']:
1046
+ amount = self.from_ev(amount, market)
1047
+ return [
1048
+ self.parse_number(self.from_ep(self.safe_string(bidask, priceKey), market)),
1049
+ self.parse_number(amount),
1050
+ ]
1051
+
1052
+ def custom_parse_order_book(self, orderbook, symbol, timestamp=None, bidsKey='bids', asksKey='asks', priceKey=0, amountKey=1, market: Market = None):
1053
+ result: dict = {
1054
+ 'symbol': symbol,
1055
+ 'timestamp': timestamp,
1056
+ 'datetime': self.iso8601(timestamp),
1057
+ 'nonce': None,
1058
+ }
1059
+ sides = [bidsKey, asksKey]
1060
+ for i in range(0, len(sides)):
1061
+ side = sides[i]
1062
+ orders = []
1063
+ bidasks = self.safe_value(orderbook, side)
1064
+ for k in range(0, len(bidasks)):
1065
+ orders.append(self.custom_parse_bid_ask(bidasks[k], priceKey, amountKey, market))
1066
+ result[side] = orders
1067
+ result[bidsKey] = self.sort_by(result[bidsKey], 0, True)
1068
+ result[asksKey] = self.sort_by(result[asksKey], 0)
1069
+ return result
1070
+
1071
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1072
+ """
1073
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1074
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryorderbook
1075
+ :param str symbol: unified symbol of the market to fetch the order book for
1076
+ :param int [limit]: the maximum amount of order book entries to return
1077
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1078
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1079
+ """
1080
+ await self.load_markets()
1081
+ market = self.market(symbol)
1082
+ request: dict = {
1083
+ 'symbol': market['id'],
1084
+ # 'id': 123456789, # optional request id
1085
+ }
1086
+ response = None
1087
+ if market['linear'] and market['settle'] == 'USDT':
1088
+ response = await self.v2GetMdV2Orderbook(self.extend(request, params))
1089
+ else:
1090
+ if (limit is not None) and (limit <= 30):
1091
+ response = await self.v1GetMdOrderbook(self.extend(request, params))
1092
+ else:
1093
+ response = await self.v1GetMdFullbook(self.extend(request, params))
1094
+ #
1095
+ # {
1096
+ # "error": null,
1097
+ # "id": 0,
1098
+ # "result": {
1099
+ # "book": {
1100
+ # "asks": [
1101
+ # [23415000000, 105262000],
1102
+ # [23416000000, 147914000],
1103
+ # [23419000000, 160914000],
1104
+ # ],
1105
+ # "bids": [
1106
+ # [23360000000, 32995000],
1107
+ # [23359000000, 221887000],
1108
+ # [23356000000, 284599000],
1109
+ # ],
1110
+ # },
1111
+ # "depth": 30,
1112
+ # "sequence": 1592059928,
1113
+ # "symbol": "sETHUSDT",
1114
+ # "timestamp": 1592387340020000955,
1115
+ # "type": "snapshot"
1116
+ # }
1117
+ # }
1118
+ #
1119
+ result = self.safe_value(response, 'result', {})
1120
+ book = self.safe_value_2(result, 'book', 'orderbook_p', {})
1121
+ timestamp = self.safe_integer_product(result, 'timestamp', 0.000001)
1122
+ orderbook = self.custom_parse_order_book(book, symbol, timestamp, 'bids', 'asks', 0, 1, market)
1123
+ orderbook['nonce'] = self.safe_integer(result, 'sequence')
1124
+ return orderbook
1125
+
1126
+ def to_en(self, n, scale):
1127
+ stringN = self.number_to_string(n)
1128
+ precise = Precise(stringN)
1129
+ precise.decimals = precise.decimals - scale
1130
+ precise.reduce()
1131
+ preciseString = str(precise)
1132
+ return self.parse_to_int(preciseString)
1133
+
1134
+ def to_ev(self, amount, market: Market = None):
1135
+ if (amount is None) or (market is None):
1136
+ return amount
1137
+ return self.to_en(amount, market['valueScale'])
1138
+
1139
+ def to_ep(self, price, market: Market = None):
1140
+ if (price is None) or (market is None):
1141
+ return price
1142
+ return self.to_en(price, market['priceScale'])
1143
+
1144
+ def from_en(self, en, scale):
1145
+ if en is None:
1146
+ return None
1147
+ precise = Precise(en)
1148
+ precise.decimals = self.sum(precise.decimals, scale)
1149
+ precise.reduce()
1150
+ return str(precise)
1151
+
1152
+ def from_ep(self, ep, market: Market = None):
1153
+ if (ep is None) or (market is None):
1154
+ return ep
1155
+ return self.from_en(ep, self.safe_integer(market, 'priceScale'))
1156
+
1157
+ def from_ev(self, ev, market: Market = None):
1158
+ if (ev is None) or (market is None):
1159
+ return ev
1160
+ return self.from_en(ev, self.safe_integer(market, 'valueScale'))
1161
+
1162
+ def from_er(self, er, market: Market = None):
1163
+ if (er is None) or (market is None):
1164
+ return er
1165
+ return self.from_en(er, self.safe_integer(market, 'ratioScale'))
1166
+
1167
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1168
+ #
1169
+ # [
1170
+ # 1592467200, # timestamp
1171
+ # 300, # interval
1172
+ # 23376000000, # last
1173
+ # 23322000000, # open
1174
+ # 23381000000, # high
1175
+ # 23315000000, # low
1176
+ # 23367000000, # close
1177
+ # 208671000, # base volume
1178
+ # 48759063370, # quote volume
1179
+ # ]
1180
+ #
1181
+ baseVolume: Num
1182
+ if (market is not None) and market['spot']:
1183
+ baseVolume = self.parse_number(self.from_ev(self.safe_string(ohlcv, 7), market))
1184
+ else:
1185
+ baseVolume = self.safe_number(ohlcv, 7)
1186
+ return [
1187
+ self.safe_timestamp(ohlcv, 0),
1188
+ self.parse_number(self.from_ep(self.safe_string(ohlcv, 3), market)),
1189
+ self.parse_number(self.from_ep(self.safe_string(ohlcv, 4), market)),
1190
+ self.parse_number(self.from_ep(self.safe_string(ohlcv, 5), market)),
1191
+ self.parse_number(self.from_ep(self.safe_string(ohlcv, 6), market)),
1192
+ baseVolume,
1193
+ ]
1194
+
1195
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1196
+ """
1197
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1198
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#querykline
1199
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#query-kline
1200
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1201
+ :param str timeframe: the length of time each candle represents
1202
+ :param int [since]: *only used for USDT settled contracts, otherwise is emulated and not supported by the exchange* timestamp in ms of the earliest candle to fetch
1203
+ :param int [limit]: the maximum amount of candles to fetch
1204
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1205
+ :param int [params.until]: *USDT settled/ linear swaps only* end time in ms
1206
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1207
+ """
1208
+ await self.load_markets()
1209
+ market = self.market(symbol)
1210
+ userLimit = limit
1211
+ request: dict = {
1212
+ 'symbol': market['id'],
1213
+ 'resolution': self.safe_string(self.timeframes, timeframe, timeframe),
1214
+ }
1215
+ until = self.safe_integer_2(params, 'until', 'to')
1216
+ params = self.omit(params, ['until'])
1217
+ usesSpecialFromToEndpoint = ((market['linear'] or market['settle'] == 'USDT')) and ((since is not None) or (until is not None))
1218
+ maxLimit = 1000
1219
+ if usesSpecialFromToEndpoint:
1220
+ maxLimit = 2000
1221
+ if limit is None:
1222
+ limit = maxLimit
1223
+ request['limit'] = min(limit, maxLimit)
1224
+ response = None
1225
+ if market['linear'] or market['settle'] == 'USDT':
1226
+ if (until is not None) or (since is not None):
1227
+ candleDuration = self.parse_timeframe(timeframe)
1228
+ if since is not None:
1229
+ since = int(round(since / 1000))
1230
+ request['from'] = since
1231
+ else:
1232
+ # when 'to' is defined since is mandatory
1233
+ since = (until / 100) - (maxLimit * candleDuration)
1234
+ if until is not None:
1235
+ request['to'] = int(round(until / 1000))
1236
+ else:
1237
+ # when since is defined 'to' is mandatory
1238
+ to = since + (maxLimit * candleDuration)
1239
+ now = self.seconds()
1240
+ if to > now:
1241
+ to = now
1242
+ request['to'] = to
1243
+ response = await self.publicGetMdV2KlineList(self.extend(request, params))
1244
+ else:
1245
+ response = await self.publicGetMdV2KlineLast(self.extend(request, params))
1246
+ else:
1247
+ if since is not None:
1248
+ # phemex also provides kline query with from/to, however, self interface is NOT recommended and does not work properly.
1249
+ # we do not send since param to the exchange, instead we calculate appropriate limit param
1250
+ duration = self.parse_timeframe(timeframe) * 1000
1251
+ timeDelta = self.milliseconds() - since
1252
+ limit = self.parse_to_int(timeDelta / duration) # setting limit to the number of candles after since
1253
+ response = await self.publicGetMdV2Kline(self.extend(request, params))
1254
+ #
1255
+ # {
1256
+ # "code":0,
1257
+ # "msg":"OK",
1258
+ # "data":{
1259
+ # "total":-1,
1260
+ # "rows":[
1261
+ # [1592467200,300,23376000000,23322000000,23381000000,23315000000,23367000000,208671000,48759063370],
1262
+ # [1592467500,300,23367000000,23314000000,23390000000,23311000000,23331000000,234820000,54848948710],
1263
+ # [1592467800,300,23331000000,23385000000,23391000000,23326000000,23387000000,152931000,35747882250],
1264
+ # ]
1265
+ # }
1266
+ # }
1267
+ #
1268
+ data = self.safe_value(response, 'data', {})
1269
+ rows = self.safe_list(data, 'rows', [])
1270
+ return self.parse_ohlcvs(rows, market, timeframe, since, userLimit)
1271
+
1272
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1273
+ #
1274
+ # spot
1275
+ #
1276
+ # {
1277
+ # "askEp": 943836000000,
1278
+ # "bidEp": 943601000000,
1279
+ # "highEp": 955946000000,
1280
+ # "lastEp": 943803000000,
1281
+ # "lowEp": 924973000000,
1282
+ # "openEp": 948693000000,
1283
+ # "symbol": "sBTCUSDT",
1284
+ # "timestamp": 1592471203505728630,
1285
+ # "turnoverEv": 111822826123103,
1286
+ # "volumeEv": 11880532281
1287
+ # }
1288
+ #
1289
+ # swap
1290
+ #
1291
+ # {
1292
+ # "askEp": 2332500,
1293
+ # "bidEp": 2331000,
1294
+ # "fundingRateEr": 10000,
1295
+ # "highEp": 2380000,
1296
+ # "indexEp": 2329057,
1297
+ # "lastEp": 2331500,
1298
+ # "lowEp": 2274000,
1299
+ # "markEp": 2329232,
1300
+ # "openEp": 2337500,
1301
+ # "openInterest": 1298050,
1302
+ # "predFundingRateEr": 19921,
1303
+ # "symbol": "ETHUSD",
1304
+ # "timestamp": 1592474241582701416,
1305
+ # "turnoverEv": 47228362330,
1306
+ # "volume": 4053863
1307
+ # }
1308
+ # linear swap v2
1309
+ #
1310
+ # {
1311
+ # "closeRp":"16820.5",
1312
+ # "fundingRateRr":"0.0001",
1313
+ # "highRp":"16962.1",
1314
+ # "indexPriceRp":"16830.15651565",
1315
+ # "lowRp":"16785",
1316
+ # "markPriceRp":"16830.97534951",
1317
+ # "openInterestRv":"1323.596",
1318
+ # "openRp":"16851.7",
1319
+ # "predFundingRateRr":"0.0001",
1320
+ # "symbol":"BTCUSDT",
1321
+ # "timestamp":"1672142789065593096",
1322
+ # "turnoverRv":"124835296.0538",
1323
+ # "volumeRq":"7406.95"
1324
+ # }
1325
+ #
1326
+ marketId = self.safe_string(ticker, 'symbol')
1327
+ market = self.safe_market(marketId, market)
1328
+ symbol = market['symbol']
1329
+ timestamp = self.safe_integer_product(ticker, 'timestamp', 0.000001)
1330
+ last = self.from_ep(self.safe_string_2(ticker, 'lastEp', 'closeRp'), market)
1331
+ quoteVolume = self.from_er(self.safe_string_2(ticker, 'turnoverEv', 'turnoverRv'), market)
1332
+ baseVolume = self.safe_string(ticker, 'volume')
1333
+ if baseVolume is None:
1334
+ baseVolume = self.from_ev(self.safe_string_2(ticker, 'volumeEv', 'volumeRq'), market)
1335
+ open = self.from_ep(self.safe_string(ticker, 'openEp'), market)
1336
+ return self.safe_ticker({
1337
+ 'symbol': symbol,
1338
+ 'timestamp': timestamp,
1339
+ 'datetime': self.iso8601(timestamp),
1340
+ 'high': self.from_ep(self.safe_string_2(ticker, 'highEp', 'highRp'), market),
1341
+ 'low': self.from_ep(self.safe_string_2(ticker, 'lowEp', 'lowRp'), market),
1342
+ 'bid': self.from_ep(self.safe_string(ticker, 'bidEp'), market),
1343
+ 'bidVolume': None,
1344
+ 'ask': self.from_ep(self.safe_string(ticker, 'askEp'), market),
1345
+ 'askVolume': None,
1346
+ 'vwap': None,
1347
+ 'open': open,
1348
+ 'close': last,
1349
+ 'last': last,
1350
+ 'previousClose': None, # previous day close
1351
+ 'change': None,
1352
+ 'percentage': None,
1353
+ 'average': None,
1354
+ 'baseVolume': baseVolume,
1355
+ 'quoteVolume': quoteVolume,
1356
+ 'info': ticker,
1357
+ }, market)
1358
+
1359
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1360
+ """
1361
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1362
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query24hrsticker
1363
+ :param str symbol: unified symbol of the market to fetch the ticker for
1364
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1365
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1366
+ """
1367
+ await self.load_markets()
1368
+ market = self.market(symbol)
1369
+ request: dict = {
1370
+ 'symbol': market['id'],
1371
+ # 'id': 123456789, # optional request id
1372
+ }
1373
+ response = None
1374
+ if market['swap']:
1375
+ if market['inverse'] or market['settle'] == 'USD':
1376
+ response = await self.v1GetMdTicker24hr(self.extend(request, params))
1377
+ else:
1378
+ response = await self.v2GetMdV2Ticker24hr(self.extend(request, params))
1379
+ else:
1380
+ response = await self.v1GetMdSpotTicker24hr(self.extend(request, params))
1381
+ #
1382
+ # spot
1383
+ #
1384
+ # {
1385
+ # "error": null,
1386
+ # "id": 0,
1387
+ # "result": {
1388
+ # "askEp": 943836000000,
1389
+ # "bidEp": 943601000000,
1390
+ # "highEp": 955946000000,
1391
+ # "lastEp": 943803000000,
1392
+ # "lowEp": 924973000000,
1393
+ # "openEp": 948693000000,
1394
+ # "symbol": "sBTCUSDT",
1395
+ # "timestamp": 1592471203505728630,
1396
+ # "turnoverEv": 111822826123103,
1397
+ # "volumeEv": 11880532281
1398
+ # }
1399
+ # }
1400
+ #
1401
+ # swap
1402
+ #
1403
+ # {
1404
+ # "error": null,
1405
+ # "id": 0,
1406
+ # "result": {
1407
+ # "askEp": 2332500,
1408
+ # "bidEp": 2331000,
1409
+ # "fundingRateEr": 10000,
1410
+ # "highEp": 2380000,
1411
+ # "indexEp": 2329057,
1412
+ # "lastEp": 2331500,
1413
+ # "lowEp": 2274000,
1414
+ # "markEp": 2329232,
1415
+ # "openEp": 2337500,
1416
+ # "openInterest": 1298050,
1417
+ # "predFundingRateEr": 19921,
1418
+ # "symbol": "ETHUSD",
1419
+ # "timestamp": 1592474241582701416,
1420
+ # "turnoverEv": 47228362330,
1421
+ # "volume": 4053863
1422
+ # }
1423
+ # }
1424
+ #
1425
+ result = self.safe_dict(response, 'result', {})
1426
+ return self.parse_ticker(result, market)
1427
+
1428
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1429
+ """
1430
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1431
+ :see: https://phemex-docs.github.io/#query-24-hours-ticker-for-all-symbols-2 # spot
1432
+ :see: https://phemex-docs.github.io/#query-24-ticker-for-all-symbols # linear
1433
+ :see: https://phemex-docs.github.io/#query-24-hours-ticker-for-all-symbols # inverse
1434
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1435
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1436
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1437
+ """
1438
+ await self.load_markets()
1439
+ market: Market = None
1440
+ if symbols is not None:
1441
+ first = self.safe_value(symbols, 0)
1442
+ market = self.market(first)
1443
+ type = None
1444
+ type, params = self.handle_market_type_and_params('fetchTickers', market, params)
1445
+ subType = None
1446
+ subType, params = self.handle_sub_type_and_params('fetchTickers', market, params)
1447
+ query = self.omit(params, 'type')
1448
+ response = None
1449
+ if type == 'spot':
1450
+ response = await self.v1GetMdSpotTicker24hrAll(query)
1451
+ elif subType == 'inverse' or self.safe_string(market, 'settle') == 'USD':
1452
+ response = await self.v1GetMdTicker24hrAll(query)
1453
+ else:
1454
+ response = await self.v2GetMdV2Ticker24hrAll(query)
1455
+ result = self.safe_list(response, 'result', [])
1456
+ return self.parse_tickers(result, symbols)
1457
+
1458
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1459
+ """
1460
+ get the list of most recent trades for a particular symbol
1461
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#querytrades
1462
+ :param str symbol: unified symbol of the market to fetch trades for
1463
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1464
+ :param int [limit]: the maximum amount of trades to fetch
1465
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1466
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1467
+ """
1468
+ await self.load_markets()
1469
+ market = self.market(symbol)
1470
+ request: dict = {
1471
+ 'symbol': market['id'],
1472
+ # 'id': 123456789, # optional request id
1473
+ }
1474
+ response = None
1475
+ if market['linear'] and market['settle'] == 'USDT':
1476
+ response = await self.v2GetMdV2Trade(self.extend(request, params))
1477
+ else:
1478
+ response = await self.v1GetMdTrade(self.extend(request, params))
1479
+ #
1480
+ # {
1481
+ # "error": null,
1482
+ # "id": 0,
1483
+ # "result": {
1484
+ # "sequence": 1315644947,
1485
+ # "symbol": "BTCUSD",
1486
+ # "trades": [
1487
+ # [1592541746712239749, 13156448570000, "Buy", 93070000, 40173],
1488
+ # [1592541740434625085, 13156447110000, "Sell", 93065000, 5000],
1489
+ # [1592541732958241616, 13156441390000, "Buy", 93070000, 3460],
1490
+ # ],
1491
+ # "type": "snapshot"
1492
+ # }
1493
+ # }
1494
+ #
1495
+ result = self.safe_value(response, 'result', {})
1496
+ trades = self.safe_value_2(result, 'trades', 'trades_p', [])
1497
+ return self.parse_trades(trades, market, since, limit)
1498
+
1499
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1500
+ #
1501
+ # fetchTrades(public) spot & contract
1502
+ #
1503
+ # [
1504
+ # 1592541746712239749,
1505
+ # 13156448570000,
1506
+ # "Buy",
1507
+ # 93070000,
1508
+ # 40173
1509
+ # ]
1510
+ #
1511
+ # fetchTrades(public) perp
1512
+ #
1513
+ # [
1514
+ # 1675690986063435800,
1515
+ # "Sell",
1516
+ # "22857.4",
1517
+ # "0.269"
1518
+ # ]
1519
+ #
1520
+ # fetchMyTrades(private)
1521
+ #
1522
+ # spot
1523
+ #
1524
+ # {
1525
+ # "qtyType": "ByQuote",
1526
+ # "transactTimeNs": 1589450974800550100,
1527
+ # "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
1528
+ # "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
1529
+ # "symbol": "sBTCUSDT",
1530
+ # "side": "Buy",
1531
+ # "priceEP": 970056000000,
1532
+ # "baseQtyEv": 0,
1533
+ # "quoteQtyEv": 1000000000,
1534
+ # "action": "New",
1535
+ # "execStatus": "MakerFill",
1536
+ # "ordStatus": "Filled",
1537
+ # "ordType": "Limit",
1538
+ # "execInst": "None",
1539
+ # "timeInForce": "GoodTillCancel",
1540
+ # "stopDirection": "UNSPECIFIED",
1541
+ # "tradeType": "Trade",
1542
+ # "stopPxEp": 0,
1543
+ # "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
1544
+ # "execPriceEp": 970056000000,
1545
+ # "execBaseQtyEv": 103000,
1546
+ # "execQuoteQtyEv": 999157680,
1547
+ # "leavesBaseQtyEv": 0,
1548
+ # "leavesQuoteQtyEv": 0,
1549
+ # "execFeeEv": 0,
1550
+ # "feeRateEr": 0
1551
+ # "baseCurrency": "BTC",
1552
+ # "quoteCurrency": "USDT",
1553
+ # "feeCurrency": "BTC"
1554
+ # }
1555
+ #
1556
+ # swap
1557
+ #
1558
+ # {
1559
+ # "transactTimeNs": 1578026629824704800,
1560
+ # "symbol": "BTCUSD",
1561
+ # "currency": "BTC",
1562
+ # "action": "Replace",
1563
+ # "side": "Sell",
1564
+ # "tradeType": "Trade",
1565
+ # "execQty": 700,
1566
+ # "execPriceEp": 71500000,
1567
+ # "orderQty": 700,
1568
+ # "priceEp": 71500000,
1569
+ # "execValueEv": 9790209,
1570
+ # "feeRateEr": -25000,
1571
+ # "execFeeEv": -2447,
1572
+ # "ordType": "Limit",
1573
+ # "execID": "b01671a1-5ddc-5def-b80a-5311522fd4bf",
1574
+ # "orderID": "b63bc982-be3a-45e0-8974-43d6375fb626",
1575
+ # "clOrdID": "uuid-1577463487504",
1576
+ # "execStatus": "MakerFill"
1577
+ # }
1578
+ # perpetual
1579
+ # {
1580
+ # "accountID": 9328670003,
1581
+ # "action": "New",
1582
+ # "actionBy": "ByUser",
1583
+ # "actionTimeNs": 1666858780876924611,
1584
+ # "addedSeq": 77751555,
1585
+ # "apRp": "0",
1586
+ # "bonusChangedAmountRv": "0",
1587
+ # "bpRp": "0",
1588
+ # "clOrdID": "c0327a7d-9064-62a9-28f6-2db9aaaa04e0",
1589
+ # "closedPnlRv": "0",
1590
+ # "closedSize": "0",
1591
+ # "code": 0,
1592
+ # "cumFeeRv": "0",
1593
+ # "cumQty": "0",
1594
+ # "cumValueRv": "0",
1595
+ # "curAccBalanceRv": "1508.489893982237",
1596
+ # "curAssignedPosBalanceRv": "24.62786650928",
1597
+ # "curBonusBalanceRv": "0",
1598
+ # "curLeverageRr": "-10",
1599
+ # "curPosSide": "Buy",
1600
+ # "curPosSize": "0.043",
1601
+ # "curPosTerm": 1,
1602
+ # "curPosValueRv": "894.0689",
1603
+ # "curRiskLimitRv": "1000000",
1604
+ # "currency": "USDT",
1605
+ # "cxlRejReason": 0,
1606
+ # "displayQty": "0.003",
1607
+ # "execFeeRv": "0",
1608
+ # "execID": "00000000-0000-0000-0000-000000000000",
1609
+ # "execPriceRp": "20723.7",
1610
+ # "execQty": "0",
1611
+ # "execSeq": 77751555,
1612
+ # "execStatus": "New",
1613
+ # "execValueRv": "0",
1614
+ # "feeRateRr": "0",
1615
+ # "leavesQty": "0.003",
1616
+ # "leavesValueRv": "63.4503",
1617
+ # "message": "No error",
1618
+ # "ordStatus": "New",
1619
+ # "ordType": "Market",
1620
+ # "orderID": "fa64c6f2-47a4-4929-aab4-b7fa9bbc4323",
1621
+ # "orderQty": "0.003",
1622
+ # "pegOffsetValueRp": "0",
1623
+ # "posSide": "Long",
1624
+ # "priceRp": "21150.1",
1625
+ # "relatedPosTerm": 1,
1626
+ # "relatedReqNum": 11,
1627
+ # "side": "Buy",
1628
+ # "slTrigger": "ByMarkPrice",
1629
+ # "stopLossRp": "0",
1630
+ # "stopPxRp": "0",
1631
+ # "symbol": "BTCUSDT",
1632
+ # "takeProfitRp": "0",
1633
+ # "timeInForce": "ImmediateOrCancel",
1634
+ # "tpTrigger": "ByLastPrice",
1635
+ # "tradeType": "Amend",
1636
+ # "transactTimeNs": 1666858780881545305,
1637
+ # "userID": 932867
1638
+ # }
1639
+ #
1640
+ # swap - USDT
1641
+ #
1642
+ # {
1643
+ # "createdAt": 1666226932259,
1644
+ # "symbol": "ETHUSDT",
1645
+ # "currency": "USDT",
1646
+ # "action": 1,
1647
+ # "tradeType": 1,
1648
+ # "execQtyRq": "0.01",
1649
+ # "execPriceRp": "1271.9",
1650
+ # "side": 1,
1651
+ # "orderQtyRq": "0.78",
1652
+ # "priceRp": "1271.9",
1653
+ # "execValueRv": "12.719",
1654
+ # "feeRateRr": "0.0001",
1655
+ # "execFeeRv": "0.0012719",
1656
+ # "ordType": 2,
1657
+ # "execId": "8718cae",
1658
+ # "execStatus": 6
1659
+ # }
1660
+ # spot with fees paid using PT token
1661
+ # "createdAt": "1714990724076",
1662
+ # "symbol": "BTCUSDT",
1663
+ # "currency": "USDT",
1664
+ # "action": "1",
1665
+ # "tradeType": "1",
1666
+ # "execQtyRq": "0.003",
1667
+ # "execPriceRp": "64935",
1668
+ # "side": "2",
1669
+ # "orderQtyRq": "0.003",
1670
+ # "priceRp": "51600",
1671
+ # "execValueRv": "194.805",
1672
+ # "feeRateRr": "0.000495",
1673
+ # "execFeeRv": "0",
1674
+ # "ordType": "3",
1675
+ # "execId": "XXXXXX",
1676
+ # "execStatus": "7",
1677
+ # "posSide": "1",
1678
+ # "ptFeeRv": "0.110012249248",
1679
+ # "ptPriceRp": "0.876524893"
1680
+ #
1681
+ priceString: Str
1682
+ amountString: Str
1683
+ timestamp: Int
1684
+ id: Str = None
1685
+ side: Str = None
1686
+ costString: Str = None
1687
+ type: Str = None
1688
+ fee = None
1689
+ feeCostString: Str = None
1690
+ feeRateString: Str = None
1691
+ feeCurrencyCode: Str = None
1692
+ marketId = self.safe_string(trade, 'symbol')
1693
+ market = self.safe_market(marketId, market)
1694
+ symbol = market['symbol']
1695
+ orderId: Str = None
1696
+ takerOrMaker: Str = None
1697
+ if isinstance(trade, list):
1698
+ tradeLength = len(trade)
1699
+ timestamp = self.safe_integer_product(trade, 0, 0.000001)
1700
+ if tradeLength > 4:
1701
+ id = self.safe_string(trade, tradeLength - 4)
1702
+ side = self.safe_string_lower(trade, tradeLength - 3)
1703
+ priceString = self.safe_string(trade, tradeLength - 2)
1704
+ amountString = self.safe_string(trade, tradeLength - 1)
1705
+ if isinstance(trade[tradeLength - 2], numbers.Real):
1706
+ priceString = self.from_ep(priceString, market)
1707
+ amountString = self.from_ev(amountString, market)
1708
+ else:
1709
+ timestamp = self.safe_integer_product(trade, 'transactTimeNs', 0.000001)
1710
+ if timestamp is None:
1711
+ timestamp = self.safe_integer(trade, 'createdAt')
1712
+ id = self.safe_string_2(trade, 'execId', 'execID')
1713
+ orderId = self.safe_string(trade, 'orderID')
1714
+ if market['settle'] == 'USDT':
1715
+ sideId = self.safe_string_lower(trade, 'side')
1716
+ if (sideId == 'buy') or (sideId == 'sell'):
1717
+ side = sideId
1718
+ elif sideId is not None:
1719
+ side = 'buy' if (sideId == '1') else 'sell'
1720
+ ordType = self.safe_string(trade, 'ordType')
1721
+ if ordType == '1':
1722
+ type = 'market'
1723
+ elif ordType == '2':
1724
+ type = 'limit'
1725
+ priceString = self.safe_string(trade, 'execPriceRp')
1726
+ amountString = self.safe_string(trade, 'execQtyRq')
1727
+ costString = self.safe_string(trade, 'execValueRv')
1728
+ feeCostString = self.omit_zero(self.safe_string(trade, 'execFeeRv'))
1729
+ feeRateString = self.safe_string(trade, 'feeRateRr')
1730
+ if feeCostString is not None:
1731
+ currencyId = self.safe_string(trade, 'currency')
1732
+ feeCurrencyCode = self.safe_currency_code(currencyId)
1733
+ else:
1734
+ ptFeeRv = self.omit_zero(self.safe_string(trade, 'ptFeeRv'))
1735
+ if ptFeeRv is not None:
1736
+ feeCostString = ptFeeRv
1737
+ feeCurrencyCode = 'PT'
1738
+ else:
1739
+ side = self.safe_string_lower(trade, 'side')
1740
+ type = self.parse_order_type(self.safe_string(trade, 'ordType'))
1741
+ execStatus = self.safe_string(trade, 'execStatus')
1742
+ if execStatus == 'MakerFill':
1743
+ takerOrMaker = 'maker'
1744
+ priceString = self.from_ep(self.safe_string(trade, 'execPriceEp'), market)
1745
+ amountString = self.from_ev(self.safe_string(trade, 'execBaseQtyEv'), market)
1746
+ amountString = self.safe_string(trade, 'execQty', amountString)
1747
+ costString = self.from_er(self.safe_string_2(trade, 'execQuoteQtyEv', 'execValueEv'), market)
1748
+ feeCostString = self.from_er(self.omit_zero(self.safe_string(trade, 'execFeeEv')), market)
1749
+ if feeCostString is not None:
1750
+ feeRateString = self.from_er(self.safe_string(trade, 'feeRateEr'), market)
1751
+ if market['spot']:
1752
+ feeCurrencyCode = self.safe_currency_code(self.safe_string(trade, 'feeCurrency'))
1753
+ else:
1754
+ info = self.safe_value(market, 'info')
1755
+ if info is not None:
1756
+ settlementCurrencyId = self.safe_string(info, 'settlementCurrency')
1757
+ feeCurrencyCode = self.safe_currency_code(settlementCurrencyId)
1758
+ else:
1759
+ feeCostString = self.safe_string(trade, 'ptFeeRv')
1760
+ if feeCostString is not None:
1761
+ feeCurrencyCode = 'PT'
1762
+ fee = {
1763
+ 'cost': feeCostString,
1764
+ 'rate': feeRateString,
1765
+ 'currency': feeCurrencyCode,
1766
+ }
1767
+ return self.safe_trade({
1768
+ 'info': trade,
1769
+ 'id': id,
1770
+ 'symbol': symbol,
1771
+ 'timestamp': timestamp,
1772
+ 'datetime': self.iso8601(timestamp),
1773
+ 'order': orderId,
1774
+ 'type': type,
1775
+ 'side': side,
1776
+ 'takerOrMaker': takerOrMaker,
1777
+ 'price': priceString,
1778
+ 'amount': amountString,
1779
+ 'cost': costString,
1780
+ 'fee': fee,
1781
+ }, market)
1782
+
1783
+ def parse_spot_balance(self, response):
1784
+ #
1785
+ # {
1786
+ # "code":0,
1787
+ # "msg":"",
1788
+ # "data":[
1789
+ # {
1790
+ # "currency":"USDT",
1791
+ # "balanceEv":0,
1792
+ # "lockedTradingBalanceEv":0,
1793
+ # "lockedWithdrawEv":0,
1794
+ # "lastUpdateTimeNs":1592065834511322514,
1795
+ # "walletVid":0
1796
+ # },
1797
+ # {
1798
+ # "currency":"ETH",
1799
+ # "balanceEv":0,
1800
+ # "lockedTradingBalanceEv":0,
1801
+ # "lockedWithdrawEv":0,
1802
+ # "lastUpdateTimeNs":1592065834511322514,
1803
+ # "walletVid":0
1804
+ # }
1805
+ # ]
1806
+ # }
1807
+ #
1808
+ timestamp = None
1809
+ result: dict = {'info': response}
1810
+ data = self.safe_value(response, 'data', [])
1811
+ for i in range(0, len(data)):
1812
+ balance = data[i]
1813
+ currencyId = self.safe_string(balance, 'currency')
1814
+ code = self.safe_currency_code(currencyId)
1815
+ currency = self.safe_value(self.currencies, code, {})
1816
+ scale = self.safe_integer(currency, 'valueScale', 8)
1817
+ account = self.account()
1818
+ balanceEv = self.safe_string(balance, 'balanceEv')
1819
+ lockedTradingBalanceEv = self.safe_string(balance, 'lockedTradingBalanceEv')
1820
+ lockedWithdrawEv = self.safe_string(balance, 'lockedWithdrawEv')
1821
+ total = self.from_en(balanceEv, scale)
1822
+ lockedTradingBalance = self.from_en(lockedTradingBalanceEv, scale)
1823
+ lockedWithdraw = self.from_en(lockedWithdrawEv, scale)
1824
+ used = Precise.string_add(lockedTradingBalance, lockedWithdraw)
1825
+ lastUpdateTimeNs = self.safe_integer_product(balance, 'lastUpdateTimeNs', 0.000001)
1826
+ timestamp = lastUpdateTimeNs if (timestamp is None) else max(timestamp, lastUpdateTimeNs)
1827
+ account['total'] = total
1828
+ account['used'] = used
1829
+ result[code] = account
1830
+ result['timestamp'] = timestamp
1831
+ result['datetime'] = self.iso8601(timestamp)
1832
+ return self.safe_balance(result)
1833
+
1834
+ def parse_swap_balance(self, response):
1835
+ # usdt
1836
+ # {
1837
+ # "info": {
1838
+ # "code": "0",
1839
+ # "msg": '',
1840
+ # "data": {
1841
+ # "account": {
1842
+ # "userID": "940666",
1843
+ # "accountId": "9406660003",
1844
+ # "currency": "USDT",
1845
+ # "accountBalanceRv": "99.93143972",
1846
+ # "totalUsedBalanceRv": "0.40456",
1847
+ # "bonusBalanceRv": "0"
1848
+ # },
1849
+ # }
1850
+ #
1851
+ # {
1852
+ # "code":0,
1853
+ # "msg":"",
1854
+ # "data":{
1855
+ # "account":{
1856
+ # "accountId":6192120001,
1857
+ # "currency":"BTC",
1858
+ # "accountBalanceEv":1254744,
1859
+ # "totalUsedBalanceEv":0,
1860
+ # "bonusBalanceEv":1254744
1861
+ # }
1862
+ # }
1863
+ # }
1864
+ #
1865
+ result: dict = {'info': response}
1866
+ data = self.safe_value(response, 'data', {})
1867
+ balance = self.safe_value(data, 'account', {})
1868
+ currencyId = self.safe_string(balance, 'currency')
1869
+ code = self.safe_currency_code(currencyId)
1870
+ currency = self.currency(code)
1871
+ valueScale = self.safe_integer(currency, 'valueScale', 8)
1872
+ account = self.account()
1873
+ accountBalanceEv = self.safe_string_2(balance, 'accountBalanceEv', 'accountBalanceRv')
1874
+ totalUsedBalanceEv = self.safe_string_2(balance, 'totalUsedBalanceEv', 'totalUsedBalanceRv')
1875
+ needsConversion = (code != 'USDT')
1876
+ account['total'] = self.from_en(accountBalanceEv, valueScale) if needsConversion else accountBalanceEv
1877
+ account['used'] = self.from_en(totalUsedBalanceEv, valueScale) if needsConversion else totalUsedBalanceEv
1878
+ result[code] = account
1879
+ return self.safe_balance(result)
1880
+
1881
+ async def fetch_balance(self, params={}) -> Balances:
1882
+ """
1883
+ query for balance and get the amount of funds available for trading or funds locked in orders
1884
+ :see: https://phemex-docs.github.io/#query-wallets
1885
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query-account-positions
1886
+ :see: https://phemex-docs.github.io/#query-trading-account-and-positions
1887
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1888
+ :param str [params.type]: spot or swap
1889
+ :param str [params.code]: *swap only* currency code of the balance to query(USD, USDT, etc), default is USDT
1890
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1891
+ """
1892
+ await self.load_markets()
1893
+ type = None
1894
+ type, params = self.handle_market_type_and_params('fetchBalance', None, params)
1895
+ code = self.safe_string(params, 'code')
1896
+ params = self.omit(params, ['code'])
1897
+ response = None
1898
+ request: dict = {}
1899
+ if (type != 'spot') and (type != 'swap'):
1900
+ raise BadRequest(self.id + ' does not support ' + type + ' markets, only spot and swap')
1901
+ if type == 'swap':
1902
+ settle = None
1903
+ settle, params = self.handle_option_and_params(params, 'fetchBalance', 'settle', 'USDT')
1904
+ if code is not None or settle is not None:
1905
+ coin = None
1906
+ if code is not None:
1907
+ coin = code
1908
+ else:
1909
+ coin = settle
1910
+ currency = self.currency(coin)
1911
+ request['currency'] = currency['id']
1912
+ if currency['id'] == 'USDT':
1913
+ response = await self.privateGetGAccountsAccountPositions(self.extend(request, params))
1914
+ else:
1915
+ response = await self.privateGetAccountsAccountPositions(self.extend(request, params))
1916
+ else:
1917
+ currency = self.safe_string(params, 'currency')
1918
+ if currency is None:
1919
+ raise ArgumentsRequired(self.id + ' fetchBalance() requires a code parameter or a currency or settle parameter for ' + type + ' type')
1920
+ response = await self.privateGetSpotWallets(self.extend(request, params))
1921
+ else:
1922
+ response = await self.privateGetSpotWallets(self.extend(request, params))
1923
+ #
1924
+ # usdt
1925
+ # {
1926
+ # "info": {
1927
+ # "code": "0",
1928
+ # "msg": '',
1929
+ # "data": {
1930
+ # "account": {
1931
+ # "userID": "940666",
1932
+ # "accountId": "9406660003",
1933
+ # "currency": "USDT",
1934
+ # "accountBalanceRv": "99.93143972",
1935
+ # "totalUsedBalanceRv": "0.40456",
1936
+ # "bonusBalanceRv": "0"
1937
+ # },
1938
+ # }
1939
+ #
1940
+ # spot
1941
+ #
1942
+ # {
1943
+ # "code":0,
1944
+ # "msg":"",
1945
+ # "data":[
1946
+ # {
1947
+ # "currency":"USDT",
1948
+ # "balanceEv":0,
1949
+ # "lockedTradingBalanceEv":0,
1950
+ # "lockedWithdrawEv":0,
1951
+ # "lastUpdateTimeNs":1592065834511322514,
1952
+ # "walletVid":0
1953
+ # },
1954
+ # {
1955
+ # "currency":"ETH",
1956
+ # "balanceEv":0,
1957
+ # "lockedTradingBalanceEv":0,
1958
+ # "lockedWithdrawEv":0,
1959
+ # "lastUpdateTimeNs":1592065834511322514,
1960
+ # "walletVid":0
1961
+ # }
1962
+ # ]
1963
+ # }
1964
+ #
1965
+ # swap
1966
+ #
1967
+ # {
1968
+ # "code":0,
1969
+ # "msg":"",
1970
+ # "data":{
1971
+ # "account":{
1972
+ # "accountId":6192120001,
1973
+ # "currency":"BTC",
1974
+ # "accountBalanceEv":1254744,
1975
+ # "totalUsedBalanceEv":0,
1976
+ # "bonusBalanceEv":1254744
1977
+ # },
1978
+ # "positions":[
1979
+ # {
1980
+ # "accountID":6192120001,
1981
+ # "symbol":"BTCUSD",
1982
+ # "currency":"BTC",
1983
+ # "side":"None",
1984
+ # "positionStatus":"Normal",
1985
+ # "crossMargin":false,
1986
+ # "leverageEr":0,
1987
+ # "leverage":0E-8,
1988
+ # "initMarginReqEr":1000000,
1989
+ # "initMarginReq":0.01000000,
1990
+ # "maintMarginReqEr":500000,
1991
+ # "maintMarginReq":0.00500000,
1992
+ # "riskLimitEv":10000000000,
1993
+ # "riskLimit":100.00000000,
1994
+ # "size":0,
1995
+ # "value":0E-8,
1996
+ # "valueEv":0,
1997
+ # "avgEntryPriceEp":0,
1998
+ # "avgEntryPrice":0E-8,
1999
+ # "posCostEv":0,
2000
+ # "posCost":0E-8,
2001
+ # "assignedPosBalanceEv":0,
2002
+ # "assignedPosBalance":0E-8,
2003
+ # "bankruptCommEv":0,
2004
+ # "bankruptComm":0E-8,
2005
+ # "bankruptPriceEp":0,
2006
+ # "bankruptPrice":0E-8,
2007
+ # "positionMarginEv":0,
2008
+ # "positionMargin":0E-8,
2009
+ # "liquidationPriceEp":0,
2010
+ # "liquidationPrice":0E-8,
2011
+ # "deleveragePercentileEr":0,
2012
+ # "deleveragePercentile":0E-8,
2013
+ # "buyValueToCostEr":1150750,
2014
+ # "buyValueToCost":0.01150750,
2015
+ # "sellValueToCostEr":1149250,
2016
+ # "sellValueToCost":0.01149250,
2017
+ # "markPriceEp":96359083,
2018
+ # "markPrice":9635.90830000,
2019
+ # "markValueEv":0,
2020
+ # "markValue":null,
2021
+ # "unRealisedPosLossEv":0,
2022
+ # "unRealisedPosLoss":null,
2023
+ # "estimatedOrdLossEv":0,
2024
+ # "estimatedOrdLoss":0E-8,
2025
+ # "usedBalanceEv":0,
2026
+ # "usedBalance":0E-8,
2027
+ # "takeProfitEp":0,
2028
+ # "takeProfit":null,
2029
+ # "stopLossEp":0,
2030
+ # "stopLoss":null,
2031
+ # "realisedPnlEv":0,
2032
+ # "realisedPnl":null,
2033
+ # "cumRealisedPnlEv":0,
2034
+ # "cumRealisedPnl":null
2035
+ # }
2036
+ # ]
2037
+ # }
2038
+ # }
2039
+ #
2040
+ result = self.parse_swap_balance(response) if (type == 'swap') else self.parse_spot_balance(response)
2041
+ return result
2042
+
2043
+ def parse_order_status(self, status: Str):
2044
+ statuses: dict = {
2045
+ 'Created': 'open',
2046
+ 'Untriggered': 'open',
2047
+ 'Deactivated': 'closed',
2048
+ 'Triggered': 'open',
2049
+ 'Rejected': 'rejected',
2050
+ 'New': 'open',
2051
+ 'PartiallyFilled': 'open',
2052
+ 'Filled': 'closed',
2053
+ 'Canceled': 'canceled',
2054
+ '1': 'open',
2055
+ '2': 'canceled',
2056
+ '3': 'closed',
2057
+ '4': 'canceled',
2058
+ '5': 'open',
2059
+ '6': 'open',
2060
+ '7': 'closed',
2061
+ '8': 'canceled',
2062
+ }
2063
+ return self.safe_string(statuses, status, status)
2064
+
2065
+ def parse_order_type(self, type: Str):
2066
+ types: dict = {
2067
+ '1': 'market',
2068
+ '2': 'limit',
2069
+ '3': 'stop',
2070
+ '4': 'stopLimit',
2071
+ '5': 'market',
2072
+ '6': 'limit',
2073
+ '7': 'market',
2074
+ '8': 'market',
2075
+ '9': 'stopLimit',
2076
+ '10': 'market',
2077
+ 'Limit': 'limit',
2078
+ 'Market': 'market',
2079
+ }
2080
+ return self.safe_string(types, type, type)
2081
+
2082
+ def parse_time_in_force(self, timeInForce: Str):
2083
+ timeInForces: dict = {
2084
+ 'GoodTillCancel': 'GTC',
2085
+ 'PostOnly': 'PO',
2086
+ 'ImmediateOrCancel': 'IOC',
2087
+ 'FillOrKill': 'FOK',
2088
+ }
2089
+ return self.safe_string(timeInForces, timeInForce, timeInForce)
2090
+
2091
+ def parse_spot_order(self, order: dict, market: Market = None):
2092
+ #
2093
+ # spot
2094
+ #
2095
+ # {
2096
+ # "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
2097
+ # "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
2098
+ # "priceEp": 0,
2099
+ # "action": "New",
2100
+ # "trigger": "UNSPECIFIED",
2101
+ # "pegPriceType": "UNSPECIFIED",
2102
+ # "stopDirection": "UNSPECIFIED",
2103
+ # "bizError": 0,
2104
+ # "symbol": "sBTCUSDT",
2105
+ # "side": "Buy",
2106
+ # "baseQtyEv": 0,
2107
+ # "ordType": "Limit",
2108
+ # "timeInForce": "GoodTillCancel",
2109
+ # "ordStatus": "Created",
2110
+ # "cumFeeEv": 0,
2111
+ # "cumBaseQtyEv": 0,
2112
+ # "cumQuoteQtyEv": 0,
2113
+ # "leavesBaseQtyEv": 0,
2114
+ # "leavesQuoteQtyEv": 0,
2115
+ # "avgPriceEp": 0,
2116
+ # "cumBaseAmountEv": 0,
2117
+ # "cumQuoteAmountEv": 0,
2118
+ # "quoteQtyEv": 0,
2119
+ # "qtyType": "ByBase",
2120
+ # "stopPxEp": 0,
2121
+ # "pegOffsetValueEp": 0
2122
+ # }
2123
+ #
2124
+ # {
2125
+ # "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
2126
+ # "stopPxEp":0,
2127
+ # "avgPriceEp":0,
2128
+ # "qtyType":"ByBase",
2129
+ # "leavesBaseQtyEv":0,
2130
+ # "leavesQuoteQtyEv":0,
2131
+ # "baseQtyEv":"1000000000",
2132
+ # "feeCurrency":"4",
2133
+ # "stopDirection":"UNSPECIFIED",
2134
+ # "symbol":"sETHUSDT",
2135
+ # "side":"Buy",
2136
+ # "quoteQtyEv":250000000000,
2137
+ # "priceEp":25000000000,
2138
+ # "ordType":"Limit",
2139
+ # "timeInForce":"GoodTillCancel",
2140
+ # "ordStatus":"Rejected",
2141
+ # "execStatus":"NewRejected",
2142
+ # "createTimeNs":1592675305266037130,
2143
+ # "cumFeeEv":0,
2144
+ # "cumBaseValueEv":0,
2145
+ # "cumQuoteValueEv":0
2146
+ # }
2147
+ #
2148
+ id = self.safe_string(order, 'orderID')
2149
+ clientOrderId = self.safe_string(order, 'clOrdID')
2150
+ if (clientOrderId is not None) and (len(clientOrderId) < 1):
2151
+ clientOrderId = None
2152
+ marketId = self.safe_string(order, 'symbol')
2153
+ market = self.safe_market(marketId, market)
2154
+ symbol = market['symbol']
2155
+ price = self.from_ep(self.safe_string(order, 'priceEp'), market)
2156
+ amount = self.from_ev(self.safe_string(order, 'baseQtyEv'), market)
2157
+ remaining = self.omit_zero(self.from_ev(self.safe_string(order, 'leavesBaseQtyEv'), market))
2158
+ filled = self.from_ev(self.safe_string_2(order, 'cumBaseQtyEv', 'cumBaseValueEv'), market)
2159
+ cost = self.from_er(self.safe_string_2(order, 'cumQuoteValueEv', 'quoteQtyEv'), market)
2160
+ average = self.from_ep(self.safe_string(order, 'avgPriceEp'), market)
2161
+ status = self.parse_order_status(self.safe_string(order, 'ordStatus'))
2162
+ side = self.safe_string_lower(order, 'side')
2163
+ type = self.parse_order_type(self.safe_string(order, 'ordType'))
2164
+ timestamp = self.safe_integer_product_2(order, 'actionTimeNs', 'createTimeNs', 0.000001)
2165
+ fee = None
2166
+ feeCost = self.from_ev(self.safe_string(order, 'cumFeeEv'), market)
2167
+ if feeCost is not None:
2168
+ fee = {
2169
+ 'cost': feeCost,
2170
+ 'currency': self.safe_currency_code(self.safe_string(order, 'feeCurrency')),
2171
+ }
2172
+ timeInForce = self.parse_time_in_force(self.safe_string(order, 'timeInForce'))
2173
+ stopPrice = self.parse_number(self.omit_zero(self.from_ep(self.safe_string(order, 'stopPxEp'))))
2174
+ postOnly = (timeInForce == 'PO')
2175
+ return self.safe_order({
2176
+ 'info': order,
2177
+ 'id': id,
2178
+ 'clientOrderId': clientOrderId,
2179
+ 'timestamp': timestamp,
2180
+ 'datetime': self.iso8601(timestamp),
2181
+ 'lastTradeTimestamp': None,
2182
+ 'symbol': symbol,
2183
+ 'type': type,
2184
+ 'timeInForce': timeInForce,
2185
+ 'postOnly': postOnly,
2186
+ 'side': side,
2187
+ 'price': price,
2188
+ 'stopPrice': stopPrice,
2189
+ 'triggerPrice': stopPrice,
2190
+ 'amount': amount,
2191
+ 'cost': cost,
2192
+ 'average': average,
2193
+ 'filled': filled,
2194
+ 'remaining': remaining,
2195
+ 'status': status,
2196
+ 'fee': fee,
2197
+ 'trades': None,
2198
+ }, market)
2199
+
2200
+ def parse_order_side(self, side):
2201
+ sides: dict = {
2202
+ '1': 'buy',
2203
+ '2': 'sell',
2204
+ }
2205
+ return self.safe_string(sides, side, side)
2206
+
2207
+ def parse_swap_order(self, order, market: Market = None):
2208
+ #
2209
+ # {
2210
+ # "bizError":0,
2211
+ # "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
2212
+ # "clOrdID":"",
2213
+ # "symbol":"ETHUSD",
2214
+ # "side":"Buy",
2215
+ # "actionTimeNs":1592668973945065381,
2216
+ # "transactTimeNs":0,
2217
+ # "orderType":"Market",
2218
+ # "priceEp":2267500,
2219
+ # "price":226.75000000,
2220
+ # "orderQty":1,
2221
+ # "displayQty":0,
2222
+ # "timeInForce":"ImmediateOrCancel",
2223
+ # "reduceOnly":false,
2224
+ # "closedPnlEv":0,
2225
+ # "closedPnl":0E-8,
2226
+ # "closedSize":0,
2227
+ # "cumQty":0,
2228
+ # "cumValueEv":0,
2229
+ # "cumValue":0E-8,
2230
+ # "leavesQty":1,
2231
+ # "leavesValueEv":11337,
2232
+ # "leavesValue":1.13370000,
2233
+ # "stopDirection":"UNSPECIFIED",
2234
+ # "stopPxEp":0,
2235
+ # "stopPx":0E-8,
2236
+ # "trigger":"UNSPECIFIED",
2237
+ # "pegOffsetValueEp":0,
2238
+ # "execStatus":"PendingNew",
2239
+ # "pegPriceType":"UNSPECIFIED",
2240
+ # "ordStatus":"Created",
2241
+ # "execInst": "ReduceOnly"
2242
+ # }
2243
+ #
2244
+ # usdt
2245
+ # {
2246
+ # "bizError":"0",
2247
+ # "orderID":"bd720dff-5647-4596-aa4e-656bac87aaad",
2248
+ # "clOrdID":"ccxt2022843dffac9477b497",
2249
+ # "symbol":"LTCUSDT",
2250
+ # "side":"Buy",
2251
+ # "actionTimeNs":"1677667878751724052",
2252
+ # "transactTimeNs":"1677667878754017434",
2253
+ # "orderType":"Limit",
2254
+ # "priceRp":"40",
2255
+ # "orderQtyRq":"0.1",
2256
+ # "displayQtyRq":"0.1",
2257
+ # "timeInForce":"GoodTillCancel",
2258
+ # "reduceOnly":false,
2259
+ # "closedPnlRv":"0",
2260
+ # "closedSizeRq":"0",
2261
+ # "cumQtyRq":"0",
2262
+ # "cumValueRv":"0",
2263
+ # "leavesQtyRq":"0.1",
2264
+ # "leavesValueRv":"4",
2265
+ # "stopDirection":"UNSPECIFIED",
2266
+ # "stopPxRp":"0",
2267
+ # "trigger":"UNSPECIFIED",
2268
+ # "pegOffsetValueRp":"0",
2269
+ # "pegOffsetProportionRr":"0",
2270
+ # "execStatus":"New",
2271
+ # "pegPriceType":"UNSPECIFIED",
2272
+ # "ordStatus":"New",
2273
+ # "execInst":"None",
2274
+ # "takeProfitRp":"0",
2275
+ # "stopLossRp":"0"
2276
+ # }
2277
+ #
2278
+ # v2 orderList
2279
+ # {
2280
+ # "createdAt":"1677686231301",
2281
+ # "symbol":"LTCUSDT",
2282
+ # "orderQtyRq":"0.2",
2283
+ # "side":"1",
2284
+ # "posSide":"3",
2285
+ # "priceRp":"50",
2286
+ # "execQtyRq":"0",
2287
+ # "leavesQtyRq":"0.2",
2288
+ # "execPriceRp":"0",
2289
+ # "orderValueRv":"10",
2290
+ # "leavesValueRv":"10",
2291
+ # "cumValueRv":"0",
2292
+ # "stopDirection":"0",
2293
+ # "stopPxRp":"0",
2294
+ # "trigger":"0",
2295
+ # "actionBy":"1",
2296
+ # "execFeeRv":"0",
2297
+ # "ordType":"2",
2298
+ # "ordStatus":"5",
2299
+ # "clOrdId":"4b3b188",
2300
+ # "orderId":"4b3b1884-87cf-4897-b596-6693b7ed84d1",
2301
+ # "execStatus":"5",
2302
+ # "bizError":"0",
2303
+ # "totalPnlRv":null,
2304
+ # "avgTransactPriceRp":null,
2305
+ # "orderDetailsVos":null,
2306
+ # "tradeType":"0"
2307
+ # }
2308
+ #
2309
+ id = self.safe_string_2(order, 'orderID', 'orderId')
2310
+ clientOrderId = self.safe_string_2(order, 'clOrdID', 'clOrdId')
2311
+ if (clientOrderId is not None) and (len(clientOrderId) < 1):
2312
+ clientOrderId = None
2313
+ marketId = self.safe_string(order, 'symbol')
2314
+ symbol = self.safe_symbol(marketId, market)
2315
+ market = self.safe_market(marketId, market)
2316
+ status = self.parse_order_status(self.safe_string(order, 'ordStatus'))
2317
+ side = self.parse_order_side(self.safe_string_lower(order, 'side'))
2318
+ type = self.parse_order_type(self.safe_string(order, 'orderType'))
2319
+ price = self.safe_string(order, 'priceRp')
2320
+ if price is None:
2321
+ price = self.from_ep(self.safe_string(order, 'priceEp'), market)
2322
+ amount = self.safe_number_2(order, 'orderQty', 'orderQtyRq')
2323
+ filled = self.safe_number_2(order, 'cumQty', 'cumQtyRq')
2324
+ remaining = self.safe_number_2(order, 'leavesQty', 'leavesQtyRq')
2325
+ timestamp = self.safe_integer_product(order, 'actionTimeNs', 0.000001)
2326
+ if timestamp is None:
2327
+ timestamp = self.safe_integer(order, 'createdAt')
2328
+ cost = self.safe_number_2(order, 'cumValue', 'cumValueRv')
2329
+ lastTradeTimestamp = self.safe_integer_product(order, 'transactTimeNs', 0.000001)
2330
+ if lastTradeTimestamp == 0:
2331
+ lastTradeTimestamp = None
2332
+ timeInForce = self.parse_time_in_force(self.safe_string(order, 'timeInForce'))
2333
+ stopPrice = self.omit_zero(self.safe_string_2(order, 'stopPx', 'stopPxRp'))
2334
+ postOnly = (timeInForce == 'PO')
2335
+ reduceOnly = self.safe_value(order, 'reduceOnly')
2336
+ execInst = self.safe_string(order, 'execInst')
2337
+ if execInst == 'ReduceOnly':
2338
+ reduceOnly = True
2339
+ takeProfit = self.safe_string(order, 'takeProfitRp')
2340
+ stopLoss = self.safe_string(order, 'stopLossRp')
2341
+ feeValue = self.omit_zero(self.safe_string(order, 'execFeeRv'))
2342
+ ptFeeRv = self.omit_zero(self.safe_string(order, 'ptFeeRv'))
2343
+ fee = None
2344
+ if feeValue is not None:
2345
+ fee = {
2346
+ 'cost': feeValue,
2347
+ 'currency': market['quote'],
2348
+ }
2349
+ elif ptFeeRv is not None:
2350
+ fee = {
2351
+ 'cost': ptFeeRv,
2352
+ 'currency': 'PT',
2353
+ }
2354
+ return self.safe_order({
2355
+ 'info': order,
2356
+ 'id': id,
2357
+ 'clientOrderId': clientOrderId,
2358
+ 'datetime': self.iso8601(timestamp),
2359
+ 'timestamp': timestamp,
2360
+ 'lastTradeTimestamp': lastTradeTimestamp,
2361
+ 'symbol': symbol,
2362
+ 'type': type,
2363
+ 'timeInForce': timeInForce,
2364
+ 'postOnly': postOnly,
2365
+ 'reduceOnly': reduceOnly,
2366
+ 'side': side,
2367
+ 'price': price,
2368
+ 'stopPrice': stopPrice,
2369
+ 'triggerPrice': stopPrice,
2370
+ 'takeProfitPrice': takeProfit,
2371
+ 'stopLossPrice': stopLoss,
2372
+ 'amount': amount,
2373
+ 'filled': filled,
2374
+ 'remaining': remaining,
2375
+ 'cost': cost,
2376
+ 'average': None,
2377
+ 'status': status,
2378
+ 'fee': fee,
2379
+ 'trades': None,
2380
+ })
2381
+
2382
+ def parse_order(self, order: dict, market: Market = None) -> Order:
2383
+ isSwap = self.safe_bool(market, 'swap', False)
2384
+ hasPnl = ('closedPnl' in order) or ('closedPnlRv' in order) or ('totalPnlRv' in order)
2385
+ if isSwap or hasPnl:
2386
+ return self.parse_swap_order(order, market)
2387
+ return self.parse_spot_order(order, market)
2388
+
2389
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2390
+ """
2391
+ create a trade order
2392
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#place-order
2393
+ :see: https://phemex-docs.github.io/#place-order-http-put-prefered-3
2394
+ :param str symbol: unified symbol of the market to create an order in
2395
+ :param str type: 'market' or 'limit'
2396
+ :param str side: 'buy' or 'sell'
2397
+ :param float amount: how much of currency you want to trade in units of base currency
2398
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
2399
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2400
+ :param float [params.trigger]: trigger price for conditional orders
2401
+ :param dict [params.takeProfit]: *swap only* *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered(perpetual swap markets only)
2402
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
2403
+ :param dict [params.stopLoss]: *swap only* *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered(perpetual swap markets only)
2404
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
2405
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2406
+ """
2407
+ await self.load_markets()
2408
+ market = self.market(symbol)
2409
+ requestSide = self.capitalize(side)
2410
+ type = self.capitalize(type)
2411
+ reduceOnly = self.safe_bool(params, 'reduceOnly')
2412
+ request: dict = {
2413
+ # common
2414
+ 'symbol': market['id'],
2415
+ 'side': requestSide, # Sell, Buy
2416
+ 'ordType': type, # Market, Limit, Stop, StopLimit, MarketIfTouched, LimitIfTouched(additionally for contract-markets: MarketAsLimit, StopAsLimit, MarketIfTouchedAsLimit)
2417
+ # 'stopPxEp': self.to_ep(stopPx, market), # for conditional orders
2418
+ # 'priceEp': self.to_ep(price, market), # required for limit orders
2419
+ # 'timeInForce': 'GoodTillCancel', # GoodTillCancel, PostOnly, ImmediateOrCancel, FillOrKill
2420
+ # ----------------------------------------------------------------
2421
+ # spot
2422
+ # 'qtyType': 'ByBase', # ByBase, ByQuote
2423
+ # 'quoteQtyEv': self.to_ep(cost, market),
2424
+ # 'baseQtyEv': self.to_ev(amount, market),
2425
+ # 'trigger': 'ByLastPrice', # required for conditional orders
2426
+ # ----------------------------------------------------------------
2427
+ # swap
2428
+ # 'clOrdID': self.uuid(), # max length 40
2429
+ # 'orderQty': self.amount_to_precision(amount, symbol),
2430
+ # 'reduceOnly': False,
2431
+ # 'closeOnTrigger': False, # implicit reduceOnly and cancel other orders in the same direction
2432
+ # 'takeProfitEp': self.to_ep(takeProfit, market),
2433
+ # 'stopLossEp': self.to_ep(stopLossEp, market),
2434
+ # 'triggerType': 'ByMarkPrice', # ByMarkPrice, ByLastPrice
2435
+ # 'pegOffsetValueEp': integer, # Trailing offset from current price. Negative value when position is long, positive when position is short
2436
+ # 'pegPriceType': 'TrailingStopPeg', # TrailingTakeProfitPeg
2437
+ # 'text': 'comment',
2438
+ # 'posSide': Position direction - "Merged" for oneway mode , "Long" / "Short" for hedge mode
2439
+ }
2440
+ clientOrderId = self.safe_string_2(params, 'clOrdID', 'clientOrderId')
2441
+ stopLoss = self.safe_value(params, 'stopLoss')
2442
+ stopLossDefined = (stopLoss is not None)
2443
+ takeProfit = self.safe_value(params, 'takeProfit')
2444
+ takeProfitDefined = (takeProfit is not None)
2445
+ if clientOrderId is None:
2446
+ brokerId = self.safe_string(self.options, 'brokerId', 'CCXT123456')
2447
+ if brokerId is not None:
2448
+ request['clOrdID'] = brokerId + self.uuid16()
2449
+ else:
2450
+ request['clOrdID'] = clientOrderId
2451
+ params = self.omit(params, ['clOrdID', 'clientOrderId'])
2452
+ triggerPrice = self.safe_string_n(params, ['stopPx', 'stopPrice', 'triggerPrice'])
2453
+ if triggerPrice is not None:
2454
+ if market['settle'] == 'USDT':
2455
+ request['stopPxRp'] = self.price_to_precision(symbol, triggerPrice)
2456
+ else:
2457
+ request['stopPxEp'] = self.to_ep(triggerPrice, market)
2458
+ params = self.omit(params, ['stopPx', 'stopPrice', 'stopLoss', 'takeProfit', 'triggerPrice'])
2459
+ if market['spot']:
2460
+ qtyType = self.safe_value(params, 'qtyType', 'ByBase')
2461
+ if (type == 'Market') or (type == 'Stop') or (type == 'MarketIfTouched'):
2462
+ if price is not None:
2463
+ qtyType = 'ByQuote'
2464
+ if triggerPrice is not None:
2465
+ if type == 'Limit':
2466
+ request['ordType'] = 'StopLimit'
2467
+ elif type == 'Market':
2468
+ request['ordType'] = 'Stop'
2469
+ request['trigger'] = 'ByLastPrice'
2470
+ request['qtyType'] = qtyType
2471
+ if qtyType == 'ByQuote':
2472
+ cost = self.safe_number(params, 'cost')
2473
+ params = self.omit(params, 'cost')
2474
+ if self.options['createOrderByQuoteRequiresPrice']:
2475
+ if price is not None:
2476
+ amountString = self.number_to_string(amount)
2477
+ priceString = self.number_to_string(price)
2478
+ quoteAmount = Precise.string_mul(amountString, priceString)
2479
+ cost = self.parse_number(quoteAmount)
2480
+ elif cost is None:
2481
+ raise ArgumentsRequired(self.id + ' createOrder() ' + qtyType + ' requires a price argument or a cost parameter')
2482
+ cost = amount if (cost is None) else cost
2483
+ costString = self.number_to_string(cost)
2484
+ request['quoteQtyEv'] = self.to_ev(costString, market)
2485
+ else:
2486
+ amountString = self.number_to_string(amount)
2487
+ request['baseQtyEv'] = self.to_ev(amountString, market)
2488
+ elif market['swap']:
2489
+ posSide = self.safe_string_lower(params, 'posSide')
2490
+ if posSide is None:
2491
+ posSide = 'Merged'
2492
+ posSide = self.capitalize(posSide)
2493
+ request['posSide'] = posSide
2494
+ if reduceOnly is not None:
2495
+ request['reduceOnly'] = reduceOnly
2496
+ if market['settle'] == 'USDT':
2497
+ request['orderQtyRq'] = amount
2498
+ else:
2499
+ request['orderQty'] = self.parse_to_int(amount)
2500
+ if triggerPrice is not None:
2501
+ triggerType = self.safe_string(params, 'triggerType', 'ByMarkPrice')
2502
+ request['triggerType'] = triggerType
2503
+ if stopLossDefined or takeProfitDefined:
2504
+ if stopLossDefined:
2505
+ stopLossTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice')
2506
+ if stopLossTriggerPrice is None:
2507
+ raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["stopLoss"]["triggerPrice"], or params["stopLoss"]["stopPrice"] for a stop loss order')
2508
+ if market['settle'] == 'USDT':
2509
+ request['stopLossRp'] = self.price_to_precision(symbol, stopLossTriggerPrice)
2510
+ else:
2511
+ request['stopLossEp'] = self.to_ep(stopLossTriggerPrice, market)
2512
+ stopLossTriggerPriceType = self.safe_string_2(stopLoss, 'triggerPriceType', 'slTrigger')
2513
+ if stopLossTriggerPriceType is not None:
2514
+ if market['settle'] == 'USDT':
2515
+ if (stopLossTriggerPriceType != 'ByMarkPrice') and (stopLossTriggerPriceType != 'ByLastPrice') and (stopLossTriggerPriceType != 'ByIndexPrice') and (stopLossTriggerPriceType != 'ByAskPrice') and (stopLossTriggerPriceType != 'ByBidPrice') and (stopLossTriggerPriceType != 'ByMarkPriceLimit') and (stopLossTriggerPriceType != 'ByLastPriceLimit'):
2516
+ raise InvalidOrder(self.id + ' createOrder() take profit trigger price type must be one of "ByMarkPrice", "ByIndexPrice", "ByAskPrice", "ByBidPrice", "ByMarkPriceLimit", "ByLastPriceLimit" or "ByLastPrice"')
2517
+ else:
2518
+ if (stopLossTriggerPriceType != 'ByMarkPrice') and (stopLossTriggerPriceType != 'ByLastPrice'):
2519
+ raise InvalidOrder(self.id + ' createOrder() take profit trigger price type must be one of "ByMarkPrice", or "ByLastPrice"')
2520
+ request['slTrigger'] = stopLossTriggerPriceType
2521
+ if takeProfitDefined:
2522
+ takeProfitTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice')
2523
+ if takeProfitTriggerPrice is None:
2524
+ raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["takeProfit"]["triggerPrice"], or params["takeProfit"]["stopPrice"] for a take profit order')
2525
+ if market['settle'] == 'USDT':
2526
+ request['takeProfitRp'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
2527
+ else:
2528
+ request['takeProfitEp'] = self.to_ep(takeProfitTriggerPrice, market)
2529
+ takeProfitTriggerPriceType = self.safe_string_2(stopLoss, 'triggerPriceType', 'tpTrigger')
2530
+ if takeProfitTriggerPriceType is not None:
2531
+ if market['settle'] == 'USDT':
2532
+ if (takeProfitTriggerPriceType != 'ByMarkPrice') and (takeProfitTriggerPriceType != 'ByLastPrice') and (takeProfitTriggerPriceType != 'ByIndexPrice') and (takeProfitTriggerPriceType != 'ByAskPrice') and (takeProfitTriggerPriceType != 'ByBidPrice') and (takeProfitTriggerPriceType != 'ByMarkPriceLimit') and (takeProfitTriggerPriceType != 'ByLastPriceLimit'):
2533
+ raise InvalidOrder(self.id + ' createOrder() take profit trigger price type must be one of "ByMarkPrice", "ByIndexPrice", "ByAskPrice", "ByBidPrice", "ByMarkPriceLimit", "ByLastPriceLimit" or "ByLastPrice"')
2534
+ else:
2535
+ if (takeProfitTriggerPriceType != 'ByMarkPrice') and (takeProfitTriggerPriceType != 'ByLastPrice'):
2536
+ raise InvalidOrder(self.id + ' createOrder() take profit trigger price type must be one of "ByMarkPrice", or "ByLastPrice"')
2537
+ request['tpTrigger'] = takeProfitTriggerPriceType
2538
+ if (type == 'Limit') or (type == 'StopLimit') or (type == 'LimitIfTouched'):
2539
+ if market['settle'] == 'USDT':
2540
+ request['priceRp'] = self.price_to_precision(symbol, price)
2541
+ else:
2542
+ priceString = self.number_to_string(price)
2543
+ request['priceEp'] = self.to_ep(priceString, market)
2544
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
2545
+ if takeProfitPrice is not None:
2546
+ if market['settle'] == 'USDT':
2547
+ request['takeProfitRp'] = self.price_to_precision(symbol, takeProfitPrice)
2548
+ else:
2549
+ request['takeProfitEp'] = self.to_ep(takeProfitPrice, market)
2550
+ params = self.omit(params, 'takeProfitPrice')
2551
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
2552
+ if stopLossPrice is not None:
2553
+ if market['settle'] == 'USDT':
2554
+ request['stopLossRp'] = self.price_to_precision(symbol, stopLossPrice)
2555
+ else:
2556
+ request['stopLossEp'] = self.to_ep(stopLossPrice, market)
2557
+ params = self.omit(params, 'stopLossPrice')
2558
+ params = self.omit(params, 'reduceOnly')
2559
+ response = None
2560
+ if market['settle'] == 'USDT':
2561
+ response = await self.privatePostGOrders(self.extend(request, params))
2562
+ elif market['contract']:
2563
+ response = await self.privatePostOrders(self.extend(request, params))
2564
+ else:
2565
+ response = await self.privatePostSpotOrders(self.extend(request, params))
2566
+ #
2567
+ # spot
2568
+ #
2569
+ # {
2570
+ # "code": 0,
2571
+ # "msg": "",
2572
+ # "data": {
2573
+ # "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
2574
+ # "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
2575
+ # "priceEp": 0,
2576
+ # "action": "New",
2577
+ # "trigger": "UNSPECIFIED",
2578
+ # "pegPriceType": "UNSPECIFIED",
2579
+ # "stopDirection": "UNSPECIFIED",
2580
+ # "bizError": 0,
2581
+ # "symbol": "sBTCUSDT",
2582
+ # "side": "Buy",
2583
+ # "baseQtyEv": 0,
2584
+ # "ordType": "Limit",
2585
+ # "timeInForce": "GoodTillCancel",
2586
+ # "ordStatus": "Created",
2587
+ # "cumFeeEv": 0,
2588
+ # "cumBaseQtyEv": 0,
2589
+ # "cumQuoteQtyEv": 0,
2590
+ # "leavesBaseQtyEv": 0,
2591
+ # "leavesQuoteQtyEv": 0,
2592
+ # "avgPriceEp": 0,
2593
+ # "cumBaseAmountEv": 0,
2594
+ # "cumQuoteAmountEv": 0,
2595
+ # "quoteQtyEv": 0,
2596
+ # "qtyType": "ByBase",
2597
+ # "stopPxEp": 0,
2598
+ # "pegOffsetValueEp": 0
2599
+ # }
2600
+ # }
2601
+ #
2602
+ # swap
2603
+ #
2604
+ # {
2605
+ # "code":0,
2606
+ # "msg":"",
2607
+ # "data":{
2608
+ # "bizError":0,
2609
+ # "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
2610
+ # "clOrdID":"",
2611
+ # "symbol":"ETHUSD",
2612
+ # "side":"Buy",
2613
+ # "actionTimeNs":1592668973945065381,
2614
+ # "transactTimeNs":0,
2615
+ # "orderType":"Market",
2616
+ # "priceEp":2267500,
2617
+ # "price":226.75000000,
2618
+ # "orderQty":1,
2619
+ # "displayQty":0,
2620
+ # "timeInForce":"ImmediateOrCancel",
2621
+ # "reduceOnly":false,
2622
+ # "closedPnlEv":0,
2623
+ # "closedPnl":0E-8,
2624
+ # "closedSize":0,
2625
+ # "cumQty":0,
2626
+ # "cumValueEv":0,
2627
+ # "cumValue":0E-8,
2628
+ # "leavesQty":1,
2629
+ # "leavesValueEv":11337,
2630
+ # "leavesValue":1.13370000,
2631
+ # "stopDirection":"UNSPECIFIED",
2632
+ # "stopPxEp":0,
2633
+ # "stopPx":0E-8,
2634
+ # "trigger":"UNSPECIFIED",
2635
+ # "pegOffsetValueEp":0,
2636
+ # "execStatus":"PendingNew",
2637
+ # "pegPriceType":"UNSPECIFIED",
2638
+ # "ordStatus":"Created"
2639
+ # }
2640
+ # }
2641
+ #
2642
+ data = self.safe_dict(response, 'data', {})
2643
+ return self.parse_order(data, market)
2644
+
2645
+ async def edit_order(self, id: str, symbol: str, type: OrderType = None, side: OrderSide = None, amount: Num = None, price: Num = None, params={}):
2646
+ """
2647
+ edit a trade order
2648
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#amend-order-by-orderid
2649
+ :param str id: cancel order id
2650
+ :param str symbol: unified symbol of the market to create an order in
2651
+ :param str type: 'market' or 'limit'
2652
+ :param str side: 'buy' or 'sell'
2653
+ :param float amount: how much of currency you want to trade in units of base currency
2654
+ :param float [price]: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
2655
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2656
+ :param str [params.posSide]: either 'Merged' or 'Long' or 'Short'
2657
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2658
+ """
2659
+ await self.load_markets()
2660
+ market = self.market(symbol)
2661
+ request: dict = {
2662
+ 'symbol': market['id'],
2663
+ }
2664
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'clOrdID')
2665
+ params = self.omit(params, ['clientOrderId', 'clOrdID'])
2666
+ isUSDTSettled = (market['settle'] == 'USDT')
2667
+ if clientOrderId is not None:
2668
+ request['clOrdID'] = clientOrderId
2669
+ else:
2670
+ request['orderID'] = id
2671
+ if price is not None:
2672
+ if isUSDTSettled:
2673
+ request['priceRp'] = self.price_to_precision(market['symbol'], price)
2674
+ else:
2675
+ request['priceEp'] = self.to_ep(price, market)
2676
+ # Note the uppercase 'V' in 'baseQtyEV' request. that is exchange's requirement at self moment. However, to avoid mistakes from user side, let's support lowercased 'baseQtyEv' too
2677
+ finalQty = self.safe_string(params, 'baseQtyEv')
2678
+ params = self.omit(params, ['baseQtyEv'])
2679
+ if finalQty is not None:
2680
+ request['baseQtyEV'] = finalQty
2681
+ elif amount is not None:
2682
+ if isUSDTSettled:
2683
+ request['orderQtyRq'] = self.amount_to_precision(market['symbol'], amount)
2684
+ else:
2685
+ request['baseQtyEV'] = self.to_ev(amount, market)
2686
+ stopPrice = self.safe_string_2(params, 'stopPx', 'stopPrice')
2687
+ if stopPrice is not None:
2688
+ if isUSDTSettled:
2689
+ request['stopPxRp'] = self.price_to_precision(symbol, stopPrice)
2690
+ else:
2691
+ request['stopPxEp'] = self.to_ep(stopPrice, market)
2692
+ params = self.omit(params, ['stopPx', 'stopPrice'])
2693
+ response = None
2694
+ if isUSDTSettled:
2695
+ posSide = self.safe_string(params, 'posSide')
2696
+ if posSide is None:
2697
+ request['posSide'] = 'Merged'
2698
+ response = await self.privatePutGOrdersReplace(self.extend(request, params))
2699
+ elif market['swap']:
2700
+ response = await self.privatePutOrdersReplace(self.extend(request, params))
2701
+ else:
2702
+ response = await self.privatePutSpotOrders(self.extend(request, params))
2703
+ data = self.safe_dict(response, 'data', {})
2704
+ return self.parse_order(data, market)
2705
+
2706
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
2707
+ """
2708
+ cancels an open order
2709
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#cancel-single-order-by-orderid
2710
+ :param str id: order id
2711
+ :param str symbol: unified symbol of the market the order was made in
2712
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2713
+ :param str [params.posSide]: either 'Merged' or 'Long' or 'Short'
2714
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2715
+ """
2716
+ if symbol is None:
2717
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
2718
+ await self.load_markets()
2719
+ market = self.market(symbol)
2720
+ request: dict = {
2721
+ 'symbol': market['id'],
2722
+ }
2723
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'clOrdID')
2724
+ params = self.omit(params, ['clientOrderId', 'clOrdID'])
2725
+ if clientOrderId is not None:
2726
+ request['clOrdID'] = clientOrderId
2727
+ else:
2728
+ request['orderID'] = id
2729
+ response = None
2730
+ if market['settle'] == 'USDT':
2731
+ posSide = self.safe_string(params, 'posSide')
2732
+ if posSide is None:
2733
+ request['posSide'] = 'Merged'
2734
+ response = await self.privateDeleteGOrdersCancel(self.extend(request, params))
2735
+ elif market['swap']:
2736
+ response = await self.privateDeleteOrdersCancel(self.extend(request, params))
2737
+ else:
2738
+ response = await self.privateDeleteSpotOrders(self.extend(request, params))
2739
+ data = self.safe_dict(response, 'data', {})
2740
+ return self.parse_order(data, market)
2741
+
2742
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
2743
+ """
2744
+ cancel all open orders in a market
2745
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#cancelall
2746
+ :param str symbol: unified market symbol of the market to cancel orders in
2747
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2748
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2749
+ """
2750
+ if symbol is None:
2751
+ raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
2752
+ await self.load_markets()
2753
+ market = self.market(symbol)
2754
+ stop = self.safe_value_2(params, 'stop', 'trigger', False)
2755
+ params = self.omit(params, 'stop', 'trigger')
2756
+ request: dict = {
2757
+ 'symbol': market['id'],
2758
+ # 'untriggerred': False, # False to cancel non-conditional orders, True to cancel conditional orders
2759
+ # 'text': 'up to 40 characters max',
2760
+ }
2761
+ if stop:
2762
+ request['untriggerred'] = stop
2763
+ response = None
2764
+ if market['settle'] == 'USDT':
2765
+ response = await self.privateDeleteGOrdersAll(self.extend(request, params))
2766
+ elif market['swap']:
2767
+ response = await self.privateDeleteOrdersAll(self.extend(request, params))
2768
+ else:
2769
+ response = await self.privateDeleteSpotOrdersAll(self.extend(request, params))
2770
+ return response
2771
+
2772
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
2773
+ """
2774
+ :see: https://phemex-docs.github.io/#query-orders-by-ids
2775
+ fetches information on an order made by the user
2776
+ :param str symbol: unified symbol of the market the order was made in
2777
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2778
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2779
+ """
2780
+ if symbol is None:
2781
+ raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
2782
+ await self.load_markets()
2783
+ market = self.market(symbol)
2784
+ request: dict = {
2785
+ 'symbol': market['id'],
2786
+ }
2787
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'clOrdID')
2788
+ params = self.omit(params, ['clientOrderId', 'clOrdID'])
2789
+ if clientOrderId is not None:
2790
+ request['clOrdID'] = clientOrderId
2791
+ else:
2792
+ request['orderID'] = id
2793
+ response = None
2794
+ if market['settle'] == 'USDT':
2795
+ response = await self.privateGetApiDataGFuturesOrdersByOrderId(self.extend(request, params))
2796
+ elif market['spot']:
2797
+ response = await self.privateGetSpotOrdersActive(self.extend(request, params))
2798
+ else:
2799
+ response = await self.privateGetExchangeOrder(self.extend(request, params))
2800
+ data = self.safe_value(response, 'data', {})
2801
+ order = data
2802
+ if isinstance(data, list):
2803
+ numOrders = len(data)
2804
+ if numOrders < 1:
2805
+ if clientOrderId is not None:
2806
+ raise OrderNotFound(self.id + ' fetchOrder() ' + symbol + ' order with clientOrderId ' + clientOrderId + ' not found')
2807
+ else:
2808
+ raise OrderNotFound(self.id + ' fetchOrder() ' + symbol + ' order with id ' + id + ' not found')
2809
+ order = self.safe_value(data, 0, {})
2810
+ return self.parse_order(order, market)
2811
+
2812
+ async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2813
+ """
2814
+ fetches information on multiple orders made by the user
2815
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryorder
2816
+ :param str symbol: unified market symbol of the market orders were made in
2817
+ :param int [since]: the earliest time in ms to fetch orders for
2818
+ :param int [limit]: the maximum number of order structures to retrieve
2819
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2820
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2821
+ """
2822
+ if symbol is None:
2823
+ raise ArgumentsRequired(self.id + ' fetchOrders() requires a symbol argument')
2824
+ await self.load_markets()
2825
+ market = self.market(symbol)
2826
+ request: dict = {
2827
+ 'symbol': market['id'],
2828
+ }
2829
+ if since is not None:
2830
+ request['start'] = since
2831
+ if limit is not None:
2832
+ request['limit'] = limit
2833
+ response = None
2834
+ if market['settle'] == 'USDT':
2835
+ request['currency'] = market['settle']
2836
+ response = await self.privateGetExchangeOrderV2OrderList(self.extend(request, params))
2837
+ elif market['swap']:
2838
+ response = await self.privateGetExchangeOrderList(self.extend(request, params))
2839
+ else:
2840
+ response = await self.privateGetSpotOrders(self.extend(request, params))
2841
+ data = self.safe_value(response, 'data', {})
2842
+ rows = self.safe_list(data, 'rows', data)
2843
+ return self.parse_orders(rows, market, since, limit)
2844
+
2845
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2846
+ """
2847
+ fetch all unfilled currently open orders
2848
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryopenorder
2849
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md
2850
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#spotListAllOpenOrder
2851
+ :param str symbol: unified market symbol
2852
+ :param int [since]: the earliest time in ms to fetch open orders for
2853
+ :param int [limit]: the maximum number of open order structures to retrieve
2854
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2855
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2856
+ """
2857
+ await self.load_markets()
2858
+ if symbol is None:
2859
+ raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
2860
+ await self.load_markets()
2861
+ market = self.market(symbol)
2862
+ request: dict = {
2863
+ 'symbol': market['id'],
2864
+ }
2865
+ response = None
2866
+ try:
2867
+ if market['settle'] == 'USDT':
2868
+ response = await self.privateGetGOrdersActiveList(self.extend(request, params))
2869
+ elif market['swap']:
2870
+ response = await self.privateGetOrdersActiveList(self.extend(request, params))
2871
+ else:
2872
+ response = await self.privateGetSpotOrders(self.extend(request, params))
2873
+ except Exception as e:
2874
+ if isinstance(e, OrderNotFound):
2875
+ return []
2876
+ raise e
2877
+ data = self.safe_value(response, 'data', {})
2878
+ if isinstance(data, list):
2879
+ return self.parse_orders(data, market, since, limit)
2880
+ else:
2881
+ rows = self.safe_list(data, 'rows', [])
2882
+ return self.parse_orders(rows, market, since, limit)
2883
+
2884
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2885
+ """
2886
+ fetches information on multiple closed orders made by the user
2887
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#queryorder
2888
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#queryorder
2889
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedgedd-Perpetual-API.md#query-closed-orders-by-symbol
2890
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#spotDataOrdersByIds
2891
+ :param str symbol: unified market symbol of the market orders were made in
2892
+ :param int [since]: the earliest time in ms to fetch orders for
2893
+ :param int [limit]: the maximum number of order structures to retrieve
2894
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2895
+ :param str [params.settle]: the settlement currency to fetch orders for
2896
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2897
+ """
2898
+ await self.load_markets()
2899
+ market = None
2900
+ if symbol is not None:
2901
+ market = self.market(symbol)
2902
+ request: dict = {
2903
+ }
2904
+ if market is not None:
2905
+ request['symbol'] = market['id']
2906
+ if since is not None:
2907
+ request['start'] = since
2908
+ if limit is not None:
2909
+ request['limit'] = limit
2910
+ response = None
2911
+ if (symbol is None) or (self.safe_string(market, 'settle') == 'USDT'):
2912
+ request['currency'] = self.safe_string(params, 'settle', 'USDT')
2913
+ response = await self.privateGetExchangeOrderV2OrderList(self.extend(request, params))
2914
+ elif market['swap']:
2915
+ response = await self.privateGetExchangeOrderList(self.extend(request, params))
2916
+ else:
2917
+ response = await self.privateGetExchangeSpotOrder(self.extend(request, params))
2918
+ #
2919
+ # spot
2920
+ #
2921
+ # {
2922
+ # "code":0,
2923
+ # "msg":"OK",
2924
+ # "data":{
2925
+ # "total":8,
2926
+ # "rows":[
2927
+ # {
2928
+ # "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
2929
+ # "stopPxEp":0,
2930
+ # "avgPriceEp":0,
2931
+ # "qtyType":"ByBase",
2932
+ # "leavesBaseQtyEv":0,
2933
+ # "leavesQuoteQtyEv":0,
2934
+ # "baseQtyEv":"1000000000",
2935
+ # "feeCurrency":"4",
2936
+ # "stopDirection":"UNSPECIFIED",
2937
+ # "symbol":"sETHUSDT",
2938
+ # "side":"Buy",
2939
+ # "quoteQtyEv":250000000000,
2940
+ # "priceEp":25000000000,
2941
+ # "ordType":"Limit",
2942
+ # "timeInForce":"GoodTillCancel",
2943
+ # "ordStatus":"Rejected",
2944
+ # "execStatus":"NewRejected",
2945
+ # "createTimeNs":1592675305266037130,
2946
+ # "cumFeeEv":0,
2947
+ # "cumBaseValueEv":0,
2948
+ # "cumQuoteValueEv":0
2949
+ # },
2950
+ # ]
2951
+ # }
2952
+ # }
2953
+ #
2954
+ data = self.safe_value(response, 'data', {})
2955
+ if isinstance(data, list):
2956
+ return self.parse_orders(data, market, since, limit)
2957
+ else:
2958
+ rows = self.safe_list(data, 'rows', [])
2959
+ return self.parse_orders(rows, market, since, limit)
2960
+
2961
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2962
+ """
2963
+ fetch all trades made by the user
2964
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#query-user-trade
2965
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query-user-trade
2966
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#spotDataTradesHist
2967
+ :param str symbol: unified market symbol
2968
+ :param int [since]: the earliest time in ms to fetch trades for
2969
+ :param int [limit]: the maximum number of trades structures to retrieve
2970
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2971
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2972
+ """
2973
+ await self.load_markets()
2974
+ market = None
2975
+ if symbol is not None:
2976
+ market = self.market(symbol)
2977
+ request: dict = {}
2978
+ if limit is not None:
2979
+ limit = min(200, limit)
2980
+ request['limit'] = limit
2981
+ isUSDTSettled = (symbol is None) or (self.safe_string(market, 'settle') == 'USDT')
2982
+ if isUSDTSettled:
2983
+ request['currency'] = 'USDT'
2984
+ request['offset'] = 0
2985
+ if limit is None:
2986
+ request['limit'] = 200
2987
+ else:
2988
+ request['symbol'] = market['id']
2989
+ if since is not None:
2990
+ request['start'] = since
2991
+ response = None
2992
+ if isUSDTSettled:
2993
+ response = await self.privateGetExchangeOrderV2TradingList(self.extend(request, params))
2994
+ elif market['swap']:
2995
+ response = await self.privateGetExchangeOrderTrade(self.extend(request, params))
2996
+ else:
2997
+ response = await self.privateGetExchangeSpotOrderTrades(self.extend(request, params))
2998
+ #
2999
+ # spot
3000
+ #
3001
+ # {
3002
+ # "code": 0,
3003
+ # "msg": "OK",
3004
+ # "data": {
3005
+ # "total": 1,
3006
+ # "rows": [
3007
+ # {
3008
+ # "qtyType": "ByQuote",
3009
+ # "transactTimeNs": 1589450974800550100,
3010
+ # "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
3011
+ # "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
3012
+ # "symbol": "sBTCUSDT",
3013
+ # "side": "Buy",
3014
+ # "priceEP": 970056000000,
3015
+ # "baseQtyEv": 0,
3016
+ # "quoteQtyEv": 1000000000,
3017
+ # "action": "New",
3018
+ # "execStatus": "MakerFill",
3019
+ # "ordStatus": "Filled",
3020
+ # "ordType": "Limit",
3021
+ # "execInst": "None",
3022
+ # "timeInForce": "GoodTillCancel",
3023
+ # "stopDirection": "UNSPECIFIED",
3024
+ # "tradeType": "Trade",
3025
+ # "stopPxEp": 0,
3026
+ # "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
3027
+ # "execPriceEp": 970056000000,
3028
+ # "execBaseQtyEv": 103000,
3029
+ # "execQuoteQtyEv": 999157680,
3030
+ # "leavesBaseQtyEv": 0,
3031
+ # "leavesQuoteQtyEv": 0,
3032
+ # "execFeeEv": 0,
3033
+ # "feeRateEr": 0
3034
+ # }
3035
+ # ]
3036
+ # }
3037
+ # }
3038
+ #
3039
+ #
3040
+ # swap
3041
+ #
3042
+ # {
3043
+ # "code": 0,
3044
+ # "msg": "OK",
3045
+ # "data": {
3046
+ # "total": 79,
3047
+ # "rows": [
3048
+ # {
3049
+ # "transactTimeNs": 1606054879331565300,
3050
+ # "symbol": "BTCUSD",
3051
+ # "currency": "BTC",
3052
+ # "action": "New",
3053
+ # "side": "Buy",
3054
+ # "tradeType": "Trade",
3055
+ # "execQty": 5,
3056
+ # "execPriceEp": 182990000,
3057
+ # "orderQty": 5,
3058
+ # "priceEp": 183870000,
3059
+ # "execValueEv": 27323,
3060
+ # "feeRateEr": 75000,
3061
+ # "execFeeEv": 21,
3062
+ # "ordType": "Market",
3063
+ # "execID": "5eee56a4-04a9-5677-8eb0-c2fe22ae3645",
3064
+ # "orderID": "ee0acb82-f712-4543-a11d-d23efca73197",
3065
+ # "clOrdID": "",
3066
+ # "execStatus": "TakerFill"
3067
+ # },
3068
+ # ]
3069
+ # }
3070
+ # }
3071
+ #
3072
+ # swap - usdt
3073
+ #
3074
+ # {
3075
+ # "code": 0,
3076
+ # "msg": "OK",
3077
+ # "data": {
3078
+ # "total": 4,
3079
+ # "rows": [
3080
+ # {
3081
+ # "createdAt": 1666226932259,
3082
+ # "symbol": "ETHUSDT",
3083
+ # "currency": "USDT",
3084
+ # "action": 1,
3085
+ # "tradeType": 1,
3086
+ # "execQtyRq": "0.01",
3087
+ # "execPriceRp": "1271.9",
3088
+ # "side": 1,
3089
+ # "orderQtyRq": "0.78",
3090
+ # "priceRp": "1271.9",
3091
+ # "execValueRv": "12.719",
3092
+ # "feeRateRr": "0.0001",
3093
+ # "execFeeRv": "0.0012719",
3094
+ # "ordType": 2,
3095
+ # "execId": "8718cae",
3096
+ # "execStatus": 6
3097
+ # },
3098
+ # ]
3099
+ # }
3100
+ # }
3101
+ #
3102
+ data = None
3103
+ if isUSDTSettled:
3104
+ data = self.safe_value(response, 'data', [])
3105
+ else:
3106
+ data = self.safe_value(response, 'data', {})
3107
+ data = self.safe_value(data, 'rows', [])
3108
+ return self.parse_trades(data, market, since, limit)
3109
+
3110
+ async def fetch_deposit_address(self, code: str, params={}):
3111
+ """
3112
+ fetch the deposit address for a currency associated with self account
3113
+ :param str code: unified currency code
3114
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3115
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
3116
+ """
3117
+ await self.load_markets()
3118
+ currency = self.currency(code)
3119
+ request: dict = {
3120
+ 'currency': currency['id'],
3121
+ }
3122
+ defaultNetworks = self.safe_value(self.options, 'defaultNetworks')
3123
+ defaultNetwork = self.safe_string_upper(defaultNetworks, code)
3124
+ networks = self.safe_value(self.options, 'networks', {})
3125
+ network = self.safe_string_upper(params, 'network', defaultNetwork)
3126
+ network = self.safe_string(networks, network, network)
3127
+ if network is None:
3128
+ request['chainName'] = currency['id']
3129
+ else:
3130
+ request['chainName'] = network
3131
+ params = self.omit(params, 'network')
3132
+ response = await self.privateGetPhemexUserWalletsV2DepositAddress(self.extend(request, params))
3133
+ # {
3134
+ # "code":0,
3135
+ # "msg":"OK",
3136
+ # "data":{
3137
+ # "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
3138
+ # "tag":null
3139
+ # }
3140
+ # }
3141
+ #
3142
+ data = self.safe_value(response, 'data', {})
3143
+ address = self.safe_string(data, 'address')
3144
+ tag = self.safe_string(data, 'tag')
3145
+ self.check_address(address)
3146
+ return {
3147
+ 'currency': code,
3148
+ 'address': address,
3149
+ 'tag': tag,
3150
+ 'network': None,
3151
+ 'info': response,
3152
+ }
3153
+
3154
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3155
+ """
3156
+ fetch all deposits made to an account
3157
+ :param str code: unified currency code
3158
+ :param int [since]: the earliest time in ms to fetch deposits for
3159
+ :param int [limit]: the maximum number of deposits structures to retrieve
3160
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3161
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3162
+ """
3163
+ await self.load_markets()
3164
+ currency = None
3165
+ if code is not None:
3166
+ currency = self.currency(code)
3167
+ response = await self.privateGetExchangeWalletsDepositList(params)
3168
+ #
3169
+ # {
3170
+ # "code":0,
3171
+ # "msg":"OK",
3172
+ # "data":[
3173
+ # {
3174
+ # "id":29200,
3175
+ # "currency":"USDT",
3176
+ # "currencyCode":3,
3177
+ # "txHash":"0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
3178
+ # "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
3179
+ # "amountEv":3000000000,
3180
+ # "confirmations":13,
3181
+ # "type":"Deposit",
3182
+ # "status":"Success",
3183
+ # "createdAt":1592722565000
3184
+ # }
3185
+ # ]
3186
+ # }
3187
+ #
3188
+ data = self.safe_list(response, 'data', [])
3189
+ return self.parse_transactions(data, currency, since, limit)
3190
+
3191
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3192
+ """
3193
+ fetch all withdrawals made from an account
3194
+ :param str code: unified currency code
3195
+ :param int [since]: the earliest time in ms to fetch withdrawals for
3196
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
3197
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3198
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3199
+ """
3200
+ await self.load_markets()
3201
+ currency = None
3202
+ if code is not None:
3203
+ currency = self.currency(code)
3204
+ response = await self.privateGetExchangeWalletsWithdrawList(params)
3205
+ #
3206
+ # {
3207
+ # "code":0,
3208
+ # "msg":"OK",
3209
+ # "data":[
3210
+ # {
3211
+ # "address": "1Lxxxxxxxxxxx"
3212
+ # "amountEv": 200000
3213
+ # "currency": "BTC"
3214
+ # "currencyCode": 1
3215
+ # "expiredTime": 0
3216
+ # "feeEv": 50000
3217
+ # "rejectReason": null
3218
+ # "status": "Succeed"
3219
+ # "txHash": "44exxxxxxxxxxxxxxxxxxxxxx"
3220
+ # "withdrawStatus: ""
3221
+ # }
3222
+ # ]
3223
+ # }
3224
+ #
3225
+ data = self.safe_list(response, 'data', [])
3226
+ return self.parse_transactions(data, currency, since, limit)
3227
+
3228
+ def parse_transaction_status(self, status: Str):
3229
+ statuses: dict = {
3230
+ 'Success': 'ok',
3231
+ 'Succeed': 'ok',
3232
+ 'Rejected': 'failed',
3233
+ 'Security check failed': 'failed',
3234
+ 'SecurityCheckFailed': 'failed',
3235
+ 'Expired': 'failed',
3236
+ 'Address Risk': 'failed',
3237
+ 'Security Checking': 'pending',
3238
+ 'SecurityChecking': 'pending',
3239
+ 'Pending Review': 'pending',
3240
+ 'Pending Transfer': 'pending',
3241
+ 'AmlCsApporve': 'pending',
3242
+ 'New': 'pending',
3243
+ 'Confirmed': 'pending',
3244
+ 'Cancelled': 'canceled',
3245
+ }
3246
+ return self.safe_string(statuses, status, status)
3247
+
3248
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
3249
+ #
3250
+ # withdraw
3251
+ #
3252
+ # {
3253
+ # "id": "10000001",
3254
+ # "freezeId": null,
3255
+ # "address": "44exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
3256
+ # "amountRv": "100",
3257
+ # "chainCode": "11",
3258
+ # "chainName": "TRX",
3259
+ # "currency": "USDT",
3260
+ # "currencyCode": 3,
3261
+ # "email": "abc@gmail.com",
3262
+ # "expiredTime": "0",
3263
+ # "feeRv": "1",
3264
+ # "nickName": null,
3265
+ # "phone": null,
3266
+ # "rejectReason": "",
3267
+ # "submitedAt": "1670000000000",
3268
+ # "submittedAt": "1670000000000",
3269
+ # "txHash": null,
3270
+ # "userId": "10000001",
3271
+ # "status": "Success"
3272
+ #
3273
+ # fetchDeposits
3274
+ #
3275
+ # {
3276
+ # "id": "29200",
3277
+ # "currency": "USDT",
3278
+ # "currencyCode": "3",
3279
+ # "chainName": "ETH",
3280
+ # "chainCode": "4",
3281
+ # "txHash": "0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
3282
+ # "address": "0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
3283
+ # "amountEv": "3000000000",
3284
+ # "confirmations": "13",
3285
+ # "type": "Deposit",
3286
+ # "status": "Success",
3287
+ # "createdAt": "1592722565000",
3288
+ # }
3289
+ #
3290
+ # fetchWithdrawals
3291
+ #
3292
+ # {
3293
+ # "id": "10000001",
3294
+ # "userId": "10000001",
3295
+ # "freezeId": "10000002",
3296
+ # "phone": null,
3297
+ # "email": "abc@gmail.com",
3298
+ # "nickName": null,
3299
+ # "currency": "USDT",
3300
+ # "currencyCode": "3",
3301
+ # "status": "Succeed",
3302
+ # "withdrawStatus": "Succeed",
3303
+ # "amountEv": "8800000000",
3304
+ # "feeEv": "1200000000",
3305
+ # "address": "0x5xxxad",
3306
+ # "txHash: "0x0xxxx5d",
3307
+ # "submitedAt": "1702571922000",
3308
+ # "submittedAt": "1702571922000",
3309
+ # "expiredTime": "0",
3310
+ # "rejectReason": null,
3311
+ # "chainName": "ETH",
3312
+ # "chainCode": "4",
3313
+ # "proxyAddress": null
3314
+ # }
3315
+ #
3316
+ id = self.safe_string(transaction, 'id')
3317
+ address = self.safe_string(transaction, 'address')
3318
+ tag = None
3319
+ txid = self.safe_string(transaction, 'txHash')
3320
+ currencyId = self.safe_string(transaction, 'currency')
3321
+ currency = self.safe_currency(currencyId, currency)
3322
+ code = currency['code']
3323
+ networkId = self.safe_string(transaction, 'chainName')
3324
+ timestamp = self.safe_integer_n(transaction, ['createdAt', 'submitedAt', 'submittedAt'])
3325
+ type = self.safe_string_lower(transaction, 'type')
3326
+ feeCost = self.parse_number(self.from_en(self.safe_string(transaction, 'feeEv'), currency['valueScale']))
3327
+ if feeCost is None:
3328
+ feeCost = self.safe_number(transaction, 'feeRv')
3329
+ fee = None
3330
+ if feeCost is not None:
3331
+ type = 'withdrawal'
3332
+ fee = {
3333
+ 'cost': feeCost,
3334
+ 'currency': code,
3335
+ }
3336
+ status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
3337
+ amount = self.parse_number(self.from_en(self.safe_string(transaction, 'amountEv'), currency['valueScale']))
3338
+ if amount is None:
3339
+ amount = self.safe_number(transaction, 'amountRv')
3340
+ return {
3341
+ 'info': transaction,
3342
+ 'id': id,
3343
+ 'txid': txid,
3344
+ 'timestamp': timestamp,
3345
+ 'datetime': self.iso8601(timestamp),
3346
+ 'network': self.network_id_to_code(networkId),
3347
+ 'address': address,
3348
+ 'addressTo': address,
3349
+ 'addressFrom': None,
3350
+ 'tag': tag,
3351
+ 'tagTo': tag,
3352
+ 'tagFrom': None,
3353
+ 'type': type,
3354
+ 'amount': amount,
3355
+ 'currency': code,
3356
+ 'status': status,
3357
+ 'updated': None,
3358
+ 'comment': None,
3359
+ 'internal': None,
3360
+ 'fee': fee,
3361
+ }
3362
+
3363
+ async def fetch_positions(self, symbols: Strings = None, params={}):
3364
+ """
3365
+ fetch all open positions
3366
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#query-trading-account-and-positions
3367
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#query-account-positions
3368
+ :see: https://phemex-docs.github.io/#query-account-positions-with-unrealized-pnl
3369
+ :param str[] [symbols]: list of unified market symbols
3370
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3371
+ :param str [param.method]: *USDT contracts only* 'privateGetGAccountsAccountPositions' or 'privateGetAccountsPositions' default is 'privateGetGAccountsAccountPositions'
3372
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
3373
+ """
3374
+ await self.load_markets()
3375
+ symbols = self.market_symbols(symbols)
3376
+ subType = None
3377
+ code = self.safe_string(params, 'currency')
3378
+ settle = None
3379
+ market = None
3380
+ firstSymbol = self.safe_string(symbols, 0)
3381
+ if firstSymbol is not None:
3382
+ market = self.market(firstSymbol)
3383
+ settle = market['settle']
3384
+ code = market['settle']
3385
+ else:
3386
+ settle, params = self.handle_option_and_params(params, 'fetchPositions', 'settle', 'USD')
3387
+ subType, params = self.handle_sub_type_and_params('fetchPositions', market, params)
3388
+ isUSDTSettled = settle == 'USDT'
3389
+ if isUSDTSettled:
3390
+ code = 'USDT'
3391
+ elif code is None:
3392
+ code = 'USD' if (subType == 'linear') else 'BTC'
3393
+ else:
3394
+ params = self.omit(params, 'code')
3395
+ currency = self.currency(code)
3396
+ request: dict = {
3397
+ 'currency': currency['id'],
3398
+ }
3399
+ response = None
3400
+ if isUSDTSettled:
3401
+ method = None
3402
+ method, params = self.handle_option_and_params(params, 'fetchPositions', 'method', 'privateGetGAccountsAccountPositions')
3403
+ if method == 'privateGetGAccountsAccountPositions':
3404
+ response = await self.privateGetGAccountsAccountPositions(self.extend(request, params))
3405
+ else:
3406
+ response = await self.privateGetAccountsPositions(self.extend(request, params))
3407
+ else:
3408
+ response = await self.privateGetAccountsAccountPositions(self.extend(request, params))
3409
+ #
3410
+ # {
3411
+ # "code":0,"msg":"",
3412
+ # "data":{
3413
+ # "account":{
3414
+ # "accountId":6192120001,
3415
+ # "currency":"BTC",
3416
+ # "accountBalanceEv":1254744,
3417
+ # "totalUsedBalanceEv":0,
3418
+ # "bonusBalanceEv":1254744
3419
+ # },
3420
+ # "positions":[
3421
+ # {
3422
+ # "accountID":6192120001,
3423
+ # "symbol":"BTCUSD",
3424
+ # "currency":"BTC",
3425
+ # "side":"None",
3426
+ # "positionStatus":"Normal",
3427
+ # "crossMargin":false,
3428
+ # "leverageEr":100000000,
3429
+ # "leverage":1.00000000,
3430
+ # "initMarginReqEr":100000000,
3431
+ # "initMarginReq":1.00000000,
3432
+ # "maintMarginReqEr":500000,
3433
+ # "maintMarginReq":0.00500000,
3434
+ # "riskLimitEv":10000000000,
3435
+ # "riskLimit":100.00000000,
3436
+ # "size":0,
3437
+ # "value":0E-8,
3438
+ # "valueEv":0,
3439
+ # "avgEntryPriceEp":0,
3440
+ # "avgEntryPrice":0E-8,
3441
+ # "posCostEv":0,
3442
+ # "posCost":0E-8,
3443
+ # "assignedPosBalanceEv":0,
3444
+ # "assignedPosBalance":0E-8,
3445
+ # "bankruptCommEv":0,
3446
+ # "bankruptComm":0E-8,
3447
+ # "bankruptPriceEp":0,
3448
+ # "bankruptPrice":0E-8,
3449
+ # "positionMarginEv":0,
3450
+ # "positionMargin":0E-8,
3451
+ # "liquidationPriceEp":0,
3452
+ # "liquidationPrice":0E-8,
3453
+ # "deleveragePercentileEr":0,
3454
+ # "deleveragePercentile":0E-8,
3455
+ # "buyValueToCostEr":100225000,
3456
+ # "buyValueToCost":1.00225000,
3457
+ # "sellValueToCostEr":100075000,
3458
+ # "sellValueToCost":1.00075000,
3459
+ # "markPriceEp":135736070,
3460
+ # "markPrice":13573.60700000,
3461
+ # "markValueEv":0,
3462
+ # "markValue":null,
3463
+ # "unRealisedPosLossEv":0,
3464
+ # "unRealisedPosLoss":null,
3465
+ # "estimatedOrdLossEv":0,
3466
+ # "estimatedOrdLoss":0E-8,
3467
+ # "usedBalanceEv":0,
3468
+ # "usedBalance":0E-8,
3469
+ # "takeProfitEp":0,
3470
+ # "takeProfit":null,
3471
+ # "stopLossEp":0,
3472
+ # "stopLoss":null,
3473
+ # "cumClosedPnlEv":0,
3474
+ # "cumFundingFeeEv":0,
3475
+ # "cumTransactFeeEv":0,
3476
+ # "realisedPnlEv":0,
3477
+ # "realisedPnl":null,
3478
+ # "cumRealisedPnlEv":0,
3479
+ # "cumRealisedPnl":null
3480
+ # }
3481
+ # ]
3482
+ # }
3483
+ # }
3484
+ #
3485
+ data = self.safe_value(response, 'data', {})
3486
+ positions = self.safe_value(data, 'positions', [])
3487
+ result = []
3488
+ for i in range(0, len(positions)):
3489
+ position = positions[i]
3490
+ result.append(self.parse_position(position))
3491
+ return self.filter_by_array_positions(result, 'symbol', symbols, False)
3492
+
3493
+ def parse_position(self, position: dict, market: Market = None):
3494
+ #
3495
+ # {
3496
+ # "userID": "811370",
3497
+ # "accountID": "8113700002",
3498
+ # "symbol": "ETHUSD",
3499
+ # "currency": "USD",
3500
+ # "side": "Buy",
3501
+ # "positionStatus": "Normal",
3502
+ # "crossMargin": False,
3503
+ # "leverageEr": "200000000",
3504
+ # "leverage": "2.00000000",
3505
+ # "initMarginReqEr": "50000000",
3506
+ # "initMarginReq": "0.50000000",
3507
+ # "maintMarginReqEr": "1000000",
3508
+ # "maintMarginReq": "0.01000000",
3509
+ # "riskLimitEv": "5000000000",
3510
+ # "riskLimit": "500000.00000000",
3511
+ # "size": "1",
3512
+ # "value": "22.22370000",
3513
+ # "valueEv": "222237",
3514
+ # "avgEntryPriceEp": "44447400",
3515
+ # "avgEntryPrice": "4444.74000000",
3516
+ # "posCostEv": "111202",
3517
+ # "posCost": "11.12020000",
3518
+ # "assignedPosBalanceEv": "111202",
3519
+ # "assignedPosBalance": "11.12020000",
3520
+ # "bankruptCommEv": "84",
3521
+ # "bankruptComm": "0.00840000",
3522
+ # "bankruptPriceEp": "22224000",
3523
+ # "bankruptPrice": "2222.40000000",
3524
+ # "positionMarginEv": "111118",
3525
+ # "positionMargin": "11.11180000",
3526
+ # "liquidationPriceEp": "22669000",
3527
+ # "liquidationPrice": "2266.90000000",
3528
+ # "deleveragePercentileEr": "0",
3529
+ # "deleveragePercentile": "0E-8",
3530
+ # "buyValueToCostEr": "50112500",
3531
+ # "buyValueToCost": "0.50112500",
3532
+ # "sellValueToCostEr": "50187500",
3533
+ # "sellValueToCost": "0.50187500",
3534
+ # "markPriceEp": "31332499",
3535
+ # "markPrice": "3133.24990000",
3536
+ # "markValueEv": "0",
3537
+ # "markValue": null,
3538
+ # "unRealisedPosLossEv": "0",
3539
+ # "unRealisedPosLoss": null,
3540
+ # "estimatedOrdLossEv": "0",
3541
+ # "estimatedOrdLoss": "0E-8",
3542
+ # "usedBalanceEv": "111202",
3543
+ # "usedBalance": "11.12020000",
3544
+ # "takeProfitEp": "0",
3545
+ # "takeProfit": null,
3546
+ # "stopLossEp": "0",
3547
+ # "stopLoss": null,
3548
+ # "cumClosedPnlEv": "-1546",
3549
+ # "cumFundingFeeEv": "1605",
3550
+ # "cumTransactFeeEv": "8438",
3551
+ # "realisedPnlEv": "0",
3552
+ # "realisedPnl": null,
3553
+ # "cumRealisedPnlEv": "0",
3554
+ # "cumRealisedPnl": null,
3555
+ # "transactTimeNs": "1641571200001885324",
3556
+ # "takerFeeRateEr": "0",
3557
+ # "makerFeeRateEr": "0",
3558
+ # "term": "6",
3559
+ # "lastTermEndTimeNs": "1607711882505745356",
3560
+ # "lastFundingTimeNs": "1641571200000000000",
3561
+ # "curTermRealisedPnlEv": "-1567",
3562
+ # "execSeq": "12112761561"
3563
+ # }
3564
+ #
3565
+ marketId = self.safe_string(position, 'symbol')
3566
+ market = self.safe_market(marketId, market)
3567
+ symbol = market['symbol']
3568
+ collateral = self.safe_string_2(position, 'positionMargin', 'positionMarginRv')
3569
+ notionalString = self.safe_string_2(position, 'value', 'valueRv')
3570
+ maintenanceMarginPercentageString = self.safe_string_2(position, 'maintMarginReq', 'maintMarginReqRr')
3571
+ maintenanceMarginString = Precise.string_mul(notionalString, maintenanceMarginPercentageString)
3572
+ initialMarginString = self.safe_string_2(position, 'assignedPosBalance', 'assignedPosBalanceRv')
3573
+ initialMarginPercentageString = Precise.string_div(initialMarginString, notionalString)
3574
+ liquidationPrice = self.safe_number_2(position, 'liquidationPrice', 'liquidationPriceRp')
3575
+ markPriceString = self.safe_string_2(position, 'markPrice', 'markPriceRp')
3576
+ contracts = self.safe_string(position, 'size')
3577
+ contractSize = self.safe_value(market, 'contractSize')
3578
+ contractSizeString = self.number_to_string(contractSize)
3579
+ leverage = self.parse_number(Precise.string_abs((self.safe_string_2(position, 'leverage', 'leverageRr'))))
3580
+ entryPriceString = self.safe_string_2(position, 'avgEntryPrice', 'avgEntryPriceRp')
3581
+ rawSide = self.safe_string(position, 'side')
3582
+ side = None
3583
+ if rawSide is not None:
3584
+ side = 'long' if (rawSide == 'Buy') else 'short'
3585
+ priceDiff = None
3586
+ currency = self.safe_string(position, 'currency')
3587
+ if currency == 'USD':
3588
+ if side == 'long':
3589
+ priceDiff = Precise.string_sub(markPriceString, entryPriceString)
3590
+ else:
3591
+ priceDiff = Precise.string_sub(entryPriceString, markPriceString)
3592
+ else:
3593
+ # inverse
3594
+ if side == 'long':
3595
+ priceDiff = Precise.string_sub(Precise.string_div('1', entryPriceString), Precise.string_div('1', markPriceString))
3596
+ else:
3597
+ priceDiff = Precise.string_sub(Precise.string_div('1', markPriceString), Precise.string_div('1', entryPriceString))
3598
+ unrealizedPnl = Precise.string_mul(Precise.string_mul(priceDiff, contracts), contractSizeString)
3599
+ marginRatio = Precise.string_div(maintenanceMarginString, collateral)
3600
+ isCross = self.safe_value(position, 'crossMargin')
3601
+ return self.safe_position({
3602
+ 'info': position,
3603
+ 'id': None,
3604
+ 'symbol': symbol,
3605
+ 'contracts': self.parse_number(contracts),
3606
+ 'contractSize': contractSize,
3607
+ 'unrealizedPnl': self.parse_number(unrealizedPnl),
3608
+ 'leverage': leverage,
3609
+ 'liquidationPrice': liquidationPrice,
3610
+ 'collateral': self.parse_number(collateral),
3611
+ 'notional': self.parse_number(notionalString),
3612
+ 'markPrice': self.parse_number(markPriceString), # markPrice lags a bit ¯\_(ツ)_/¯
3613
+ 'lastPrice': None,
3614
+ 'entryPrice': self.parse_number(entryPriceString),
3615
+ 'timestamp': None,
3616
+ 'lastUpdateTimestamp': None,
3617
+ 'initialMargin': self.parse_number(initialMarginString),
3618
+ 'initialMarginPercentage': self.parse_number(initialMarginPercentageString),
3619
+ 'maintenanceMargin': self.parse_number(maintenanceMarginString),
3620
+ 'maintenanceMarginPercentage': self.parse_number(maintenanceMarginPercentageString),
3621
+ 'marginRatio': self.parse_number(marginRatio),
3622
+ 'datetime': None,
3623
+ 'marginMode': 'cross' if isCross else 'isolated',
3624
+ 'side': side,
3625
+ 'hedged': False,
3626
+ 'percentage': None,
3627
+ 'stopLossPrice': None,
3628
+ 'takeProfitPrice': None,
3629
+ })
3630
+
3631
+ async def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3632
+ """
3633
+ fetch the history of funding payments paid and received on self account
3634
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#futureDataFundingFeesHist
3635
+ :param str symbol: unified market symbol
3636
+ :param int [since]: the earliest time in ms to fetch funding history for
3637
+ :param int [limit]: the maximum number of funding history structures to retrieve
3638
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3639
+ :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
3640
+ """
3641
+ if symbol is None:
3642
+ raise ArgumentsRequired(self.id + ' fetchFundingHistory() requires a symbol argument')
3643
+ await self.load_markets()
3644
+ market = self.market(symbol)
3645
+ request: dict = {
3646
+ 'symbol': market['id'],
3647
+ # 'limit': 20, # Page size default 20, max 200
3648
+ # 'offset': 0, # Page start default 0
3649
+ }
3650
+ if limit is not None:
3651
+ if limit > 200:
3652
+ raise BadRequest(self.id + ' fetchFundingHistory() limit argument cannot exceed 200')
3653
+ request['limit'] = limit
3654
+ response = None
3655
+ isUsdt = market['settle'] == 'USDT'
3656
+ if isUsdt:
3657
+ response = await self.privateGetApiDataGFuturesFundingFees(self.extend(request, params))
3658
+ else:
3659
+ response = await self.privateGetApiDataFuturesFundingFees(self.extend(request, params))
3660
+ #
3661
+ # {
3662
+ # "code": 0,
3663
+ # "msg": "OK",
3664
+ # "data": {
3665
+ # "rows": [
3666
+ # {
3667
+ # "symbol": "BTCUSD",
3668
+ # "currency": "BTC",
3669
+ # "execQty": 18, # "execQty" regular, but "execQtyRq" in hedge
3670
+ # "side": "Buy",
3671
+ # "execPriceEp": 360086455, # "execPriceEp" regular, but "execPriceRp" in hedge
3672
+ # "execValueEv": 49987, # "execValueEv" regular, but "execValueRv" in hedge
3673
+ # "fundingRateEr": 10000, # "fundingRateEr" regular, but "fundingRateRr" in hedge
3674
+ # "feeRateEr": 10000, # "feeRateEr" regular, but "feeRateRr" in hedge
3675
+ # "execFeeEv": 5, # "execFeeEv" regular, but "execFeeRv" in hedge
3676
+ # "createTime": 1651881600000
3677
+ # }
3678
+ # ]
3679
+ # }
3680
+ # }
3681
+ #
3682
+ data = self.safe_value(response, 'data', {})
3683
+ rows = self.safe_value(data, 'rows', [])
3684
+ result = []
3685
+ for i in range(0, len(rows)):
3686
+ entry = rows[i]
3687
+ timestamp = self.safe_integer(entry, 'createTime')
3688
+ execFee = self.safe_string_2(entry, 'execFeeEv', 'execFeeRv')
3689
+ currencyCode = self.safe_currency_code(self.safe_string(entry, 'currency'))
3690
+ result.append({
3691
+ 'info': entry,
3692
+ 'symbol': self.safe_string(entry, 'symbol'),
3693
+ 'code': currencyCode,
3694
+ 'timestamp': timestamp,
3695
+ 'datetime': self.iso8601(timestamp),
3696
+ 'id': None,
3697
+ 'amount': self.parse_funding_fee_to_precision(execFee, market, currencyCode),
3698
+ })
3699
+ return result
3700
+
3701
+ def parse_funding_fee_to_precision(self, value, market: Market = None, currencyCode: Str = None):
3702
+ if value is None or currencyCode is None:
3703
+ return value
3704
+ # it was confirmed by phemex support, that USDT contracts use direct amounts in funding fees, while USD & INVERSE needs 'valueScale'
3705
+ isUsdt = market['settle'] == 'USDT'
3706
+ if not isUsdt:
3707
+ currency = self.safe_currency(currencyCode)
3708
+ scale = self.safe_string(currency['info'], 'valueScale')
3709
+ tickPrecision = self.parse_precision(scale)
3710
+ value = Precise.string_mul(value, tickPrecision)
3711
+ return value
3712
+
3713
+ async def fetch_funding_rate(self, symbol: str, params={}):
3714
+ """
3715
+ fetch the current funding rate
3716
+ :param str symbol: unified market symbol
3717
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3718
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
3719
+ """
3720
+ await self.load_markets()
3721
+ market = self.market(symbol)
3722
+ if not market['swap']:
3723
+ raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
3724
+ request: dict = {
3725
+ 'symbol': market['id'],
3726
+ }
3727
+ response: dict = {}
3728
+ if not market['linear']:
3729
+ response = await self.v1GetMdTicker24hr(self.extend(request, params))
3730
+ else:
3731
+ response = await self.v2GetMdV2Ticker24hr(self.extend(request, params))
3732
+ #
3733
+ # {
3734
+ # "error": null,
3735
+ # "id": 0,
3736
+ # "result": {
3737
+ # "askEp": 2332500,
3738
+ # "bidEp": 2331000,
3739
+ # "fundingRateEr": 10000,
3740
+ # "highEp": 2380000,
3741
+ # "indexEp": 2329057,
3742
+ # "lastEp": 2331500,
3743
+ # "lowEp": 2274000,
3744
+ # "markEp": 2329232,
3745
+ # "openEp": 2337500,
3746
+ # "openInterest": 1298050,
3747
+ # "predFundingRateEr": 19921,
3748
+ # "symbol": "ETHUSD",
3749
+ # "timestamp": 1592474241582701416,
3750
+ # "turnoverEv": 47228362330,
3751
+ # "volume": 4053863
3752
+ # }
3753
+ # }
3754
+ #
3755
+ result = self.safe_value(response, 'result', {})
3756
+ return self.parse_funding_rate(result, market)
3757
+
3758
+ def parse_funding_rate(self, contract, market: Market = None):
3759
+ #
3760
+ # {
3761
+ # "askEp": 2332500,
3762
+ # "bidEp": 2331000,
3763
+ # "fundingRateEr": 10000,
3764
+ # "highEp": 2380000,
3765
+ # "indexEp": 2329057,
3766
+ # "lastEp": 2331500,
3767
+ # "lowEp": 2274000,
3768
+ # "markEp": 2329232,
3769
+ # "openEp": 2337500,
3770
+ # "openInterest": 1298050,
3771
+ # "predFundingRateEr": 19921,
3772
+ # "symbol": "ETHUSD",
3773
+ # "timestamp": 1592474241582701416,
3774
+ # "turnoverEv": 47228362330,
3775
+ # "volume": 4053863
3776
+ # }
3777
+ #
3778
+ # linear swap v2
3779
+ #
3780
+ # {
3781
+ # "closeRp":"16820.5",
3782
+ # "fundingRateRr":"0.0001",
3783
+ # "highRp":"16962.1",
3784
+ # "indexPriceRp":"16830.15651565",
3785
+ # "lowRp":"16785",
3786
+ # "markPriceRp":"16830.97534951",
3787
+ # "openInterestRv":"1323.596",
3788
+ # "openRp":"16851.7",
3789
+ # "predFundingRateRr":"0.0001",
3790
+ # "symbol":"BTCUSDT",
3791
+ # "timestamp":"1672142789065593096",
3792
+ # "turnoverRv":"124835296.0538",
3793
+ # "volumeRq":"7406.95"
3794
+ # }
3795
+ #
3796
+ marketId = self.safe_string(contract, 'symbol')
3797
+ symbol = self.safe_symbol(marketId, market)
3798
+ timestamp = self.safe_integer_product(contract, 'timestamp', 0.000001)
3799
+ return {
3800
+ 'info': contract,
3801
+ 'symbol': symbol,
3802
+ 'markPrice': self.from_ep(self.safe_string_2(contract, 'markEp', 'markPriceRp'), market),
3803
+ 'indexPrice': self.from_ep(self.safe_string_2(contract, 'indexEp', 'indexPriceRp'), market),
3804
+ 'interestRate': None,
3805
+ 'estimatedSettlePrice': None,
3806
+ 'timestamp': timestamp,
3807
+ 'datetime': self.iso8601(timestamp),
3808
+ 'fundingRate': self.from_er(self.safe_string(contract, 'fundingRateEr'), market),
3809
+ 'fundingTimestamp': None,
3810
+ 'fundingDatetime': None,
3811
+ 'nextFundingRate': self.from_er(self.safe_string_2(contract, 'predFundingRateEr', 'predFundingRateRr'), market),
3812
+ 'nextFundingTimestamp': None,
3813
+ 'nextFundingDatetime': None,
3814
+ 'previousFundingRate': None,
3815
+ 'previousFundingTimestamp': None,
3816
+ 'previousFundingDatetime': None,
3817
+ }
3818
+
3819
+ async def set_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3820
+ """
3821
+ Either adds or reduces margin in an isolated position in order to set the margin to a specific value
3822
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#assign-position-balance-in-isolated-marign-mode
3823
+ :param str symbol: unified market symbol of the market to set margin in
3824
+ :param float amount: the amount to set the margin to
3825
+ :param dict [params]: parameters specific to the exchange API endpoint
3826
+ :returns dict: A `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
3827
+ """
3828
+ await self.load_markets()
3829
+ market = self.market(symbol)
3830
+ request: dict = {
3831
+ 'symbol': market['id'],
3832
+ 'posBalanceEv': self.to_ev(amount, market),
3833
+ }
3834
+ response = await self.privatePostPositionsAssign(self.extend(request, params))
3835
+ #
3836
+ # {
3837
+ # "code": 0,
3838
+ # "msg": "",
3839
+ # "data": "OK"
3840
+ # }
3841
+ #
3842
+ return self.extend(self.parse_margin_modification(response, market), {
3843
+ 'amount': amount,
3844
+ })
3845
+
3846
+ def parse_margin_status(self, status):
3847
+ statuses: dict = {
3848
+ '0': 'ok',
3849
+ }
3850
+ return self.safe_string(statuses, status, status)
3851
+
3852
+ def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
3853
+ #
3854
+ # {
3855
+ # "code": 0,
3856
+ # "msg": "",
3857
+ # "data": "OK"
3858
+ # }
3859
+ #
3860
+ market = self.safe_market(None, market)
3861
+ inverse = self.safe_value(market, 'inverse')
3862
+ codeCurrency = 'base' if inverse else 'quote'
3863
+ return {
3864
+ 'info': data,
3865
+ 'symbol': self.safe_symbol(None, market),
3866
+ 'type': 'set',
3867
+ 'marginMode': 'isolated',
3868
+ 'amount': None,
3869
+ 'total': None,
3870
+ 'code': market[codeCurrency],
3871
+ 'status': self.parse_margin_status(self.safe_string(data, 'code')),
3872
+ 'timestamp': None,
3873
+ 'datetime': None,
3874
+ }
3875
+
3876
+ async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
3877
+ """
3878
+ set margin mode to 'cross' or 'isolated'
3879
+ :param str marginMode: 'cross' or 'isolated'
3880
+ :param str symbol: unified market symbol
3881
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3882
+ :returns dict: response from the exchange
3883
+ """
3884
+ if symbol is None:
3885
+ raise ArgumentsRequired(self.id + ' setMarginMode() requires a symbol argument')
3886
+ await self.load_markets()
3887
+ market = self.market(symbol)
3888
+ if not market['swap'] or market['settle'] == 'USDT':
3889
+ raise BadSymbol(self.id + ' setMarginMode() supports swap(non USDT based) contracts only')
3890
+ marginMode = marginMode.lower()
3891
+ if marginMode != 'isolated' and marginMode != 'cross':
3892
+ raise BadRequest(self.id + ' setMarginMode() marginMode argument should be isolated or cross')
3893
+ leverage = self.safe_integer(params, 'leverage')
3894
+ if marginMode == 'cross':
3895
+ leverage = 0
3896
+ if leverage is None:
3897
+ raise ArgumentsRequired(self.id + ' setMarginMode() requires a leverage parameter')
3898
+ request: dict = {
3899
+ 'symbol': market['id'],
3900
+ 'leverage': leverage,
3901
+ }
3902
+ return await self.privatePutPositionsLeverage(self.extend(request, params))
3903
+
3904
+ async def set_position_mode(self, hedged: bool, symbol: Str = None, params={}):
3905
+ """
3906
+ set hedged to True or False for a market
3907
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#switch-position-mode-synchronously
3908
+ :param bool hedged: set to True to use dualSidePosition
3909
+ :param str symbol: not used by binance setPositionMode()
3910
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3911
+ :returns dict: response from the exchange
3912
+ """
3913
+ self.check_required_argument('setPositionMode', symbol, 'symbol')
3914
+ await self.load_markets()
3915
+ market = self.market(symbol)
3916
+ if market['settle'] != 'USDT':
3917
+ raise BadSymbol(self.id + ' setPositionMode() supports USDT settled markets only')
3918
+ request: dict = {
3919
+ 'symbol': market['id'],
3920
+ }
3921
+ if hedged:
3922
+ request['targetPosMode'] = 'Hedged'
3923
+ else:
3924
+ request['targetPosMode'] = 'OneWay'
3925
+ return await self.privatePutGPositionsSwitchPosModeSync(self.extend(request, params))
3926
+
3927
+ async def fetch_leverage_tiers(self, symbols: Strings = None, params={}) -> LeverageTiers:
3928
+ """
3929
+ retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
3930
+ :param str[]|None symbols: list of unified market symbols
3931
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3932
+ :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
3933
+ """
3934
+ await self.load_markets()
3935
+ if symbols is not None:
3936
+ first = self.safe_value(symbols, 0)
3937
+ market = self.market(first)
3938
+ if market['settle'] != 'USD':
3939
+ raise BadSymbol(self.id + ' fetchLeverageTiers() supports USD settled markets only')
3940
+ response = await self.publicGetCfgV2Products(params)
3941
+ #
3942
+ # {
3943
+ # "code":0,
3944
+ # "msg":"OK",
3945
+ # "data":{
3946
+ # "ratioScale":8,
3947
+ # "currencies":[
3948
+ # {"currency":"BTC","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"Bitcoin"},
3949
+ # {"currency":"USD","valueScale":4,"minValueEv":1,"maxValueEv":500000000000000,"name":"USD"},
3950
+ # {"currency":"USDT","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"TetherUS"},
3951
+ # ],
3952
+ # "products":[
3953
+ # {
3954
+ # "symbol":"BTCUSD",
3955
+ # "displaySymbol":"BTC / USD",
3956
+ # "indexSymbol":".BTC",
3957
+ # "markSymbol":".MBTC",
3958
+ # "fundingRateSymbol":".BTCFR",
3959
+ # "fundingRate8hSymbol":".BTCFR8H",
3960
+ # "contractUnderlyingAssets":"USD",
3961
+ # "settleCurrency":"BTC",
3962
+ # "quoteCurrency":"USD",
3963
+ # "contractSize":1.0,
3964
+ # "lotSize":1,
3965
+ # "tickSize":0.5,
3966
+ # "priceScale":4,
3967
+ # "ratioScale":8,
3968
+ # "pricePrecision":1,
3969
+ # "minPriceEp":5000,
3970
+ # "maxPriceEp":10000000000,
3971
+ # "maxOrderQty":1000000,
3972
+ # "type":"Perpetual"
3973
+ # },
3974
+ # {
3975
+ # "symbol":"sBTCUSDT",
3976
+ # "displaySymbol":"BTC / USDT",
3977
+ # "quoteCurrency":"USDT",
3978
+ # "pricePrecision":2,
3979
+ # "type":"Spot",
3980
+ # "baseCurrency":"BTC",
3981
+ # "baseTickSize":"0.000001 BTC",
3982
+ # "baseTickSizeEv":100,
3983
+ # "quoteTickSize":"0.01 USDT",
3984
+ # "quoteTickSizeEv":1000000,
3985
+ # "minOrderValue":"10 USDT",
3986
+ # "minOrderValueEv":1000000000,
3987
+ # "maxBaseOrderSize":"1000 BTC",
3988
+ # "maxBaseOrderSizeEv":100000000000,
3989
+ # "maxOrderValue":"5,000,000 USDT",
3990
+ # "maxOrderValueEv":500000000000000,
3991
+ # "defaultTakerFee":"0.001",
3992
+ # "defaultTakerFeeEr":100000,
3993
+ # "defaultMakerFee":"0.001",
3994
+ # "defaultMakerFeeEr":100000,
3995
+ # "baseQtyPrecision":6,
3996
+ # "quoteQtyPrecision":2
3997
+ # },
3998
+ # ],
3999
+ # "riskLimits":[
4000
+ # {
4001
+ # "symbol":"BTCUSD",
4002
+ # "steps":"50",
4003
+ # "riskLimits":[
4004
+ # {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
4005
+ # {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
4006
+ # {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
4007
+ # ]
4008
+ # },
4009
+ # ],
4010
+ # "leverages":[
4011
+ # {"initialMargin":"1.0%","initialMarginEr":1000000,"options":[1,2,3,5,10,25,50,100]},
4012
+ # {"initialMargin":"1.5%","initialMarginEr":1500000,"options":[1,2,3,5,10,25,50,66]},
4013
+ # {"initialMargin":"2.0%","initialMarginEr":2000000,"options":[1,2,3,5,10,25,33,50]},
4014
+ # ]
4015
+ # }
4016
+ # }
4017
+ #
4018
+ #
4019
+ data = self.safe_value(response, 'data', {})
4020
+ riskLimits = self.safe_list(data, 'riskLimits')
4021
+ return self.parse_leverage_tiers(riskLimits, symbols, 'symbol')
4022
+
4023
+ def parse_market_leverage_tiers(self, info, market: Market = None) -> List[LeverageTier]:
4024
+ """
4025
+ :param dict info: Exchange market response for 1 market
4026
+ :param dict market: CCXT market
4027
+ """
4028
+ #
4029
+ # {
4030
+ # "symbol":"BTCUSD",
4031
+ # "steps":"50",
4032
+ # "riskLimits":[
4033
+ # {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
4034
+ # {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
4035
+ # {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
4036
+ # ]
4037
+ # },
4038
+ #
4039
+ market = self.safe_market(None, market)
4040
+ riskLimits = (market['info']['riskLimits'])
4041
+ tiers = []
4042
+ minNotional = 0
4043
+ for i in range(0, len(riskLimits)):
4044
+ tier = riskLimits[i]
4045
+ maxNotional = self.safe_integer(tier, 'limit')
4046
+ tiers.append({
4047
+ 'tier': self.sum(i, 1),
4048
+ 'currency': market['settle'],
4049
+ 'minNotional': minNotional,
4050
+ 'maxNotional': maxNotional,
4051
+ 'maintenanceMarginRate': self.safe_string(tier, 'maintenanceMargin'),
4052
+ 'maxLeverage': None,
4053
+ 'info': tier,
4054
+ })
4055
+ minNotional = maxNotional
4056
+ return tiers
4057
+
4058
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
4059
+ query = self.omit(params, self.extract_params(path))
4060
+ requestPath = '/' + self.implode_params(path, params)
4061
+ url = requestPath
4062
+ queryString = ''
4063
+ if (method == 'GET') or (method == 'DELETE') or (method == 'PUT') or (url == '/positions/assign'):
4064
+ if query:
4065
+ queryString = self.urlencode_with_array_repeat(query)
4066
+ url += '?' + queryString
4067
+ if api == 'private':
4068
+ self.check_required_credentials()
4069
+ timestamp = self.seconds()
4070
+ xPhemexRequestExpiry = self.safe_integer(self.options, 'x-phemex-request-expiry', 60)
4071
+ expiry = self.sum(timestamp, xPhemexRequestExpiry)
4072
+ expiryString = str(expiry)
4073
+ headers = {
4074
+ 'x-phemex-access-token': self.apiKey,
4075
+ 'x-phemex-request-expiry': expiryString,
4076
+ }
4077
+ payload = ''
4078
+ if method == 'POST':
4079
+ isOrderPlacement = (path == 'g-orders') or (path == 'spot/orders') or (path == 'orders')
4080
+ if isOrderPlacement:
4081
+ if self.safe_string(params, 'clOrdID') is None:
4082
+ id = self.safe_string(self.options, 'brokerId', 'CCXT123456')
4083
+ params['clOrdID'] = id + self.uuid16()
4084
+ payload = self.json(params)
4085
+ body = payload
4086
+ headers['Content-Type'] = 'application/json'
4087
+ auth = requestPath + queryString + expiryString + payload
4088
+ headers['x-phemex-request-signature'] = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
4089
+ url = self.implode_hostname(self.urls['api'][api]) + url
4090
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
4091
+
4092
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
4093
+ """
4094
+ set the level of leverage for a market
4095
+ :see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#set-leverage
4096
+ :param float leverage: the rate of leverage, 100 > leverage > -100 excluding numbers between -1 to 1
4097
+ :param str symbol: unified market symbol
4098
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4099
+ :param bool [params.hedged]: set to True if hedged position mode is enabled(by default long and short leverage are set to the same value)
4100
+ :param float [params.longLeverageRr]: *hedged mode only* set the leverage for long positions
4101
+ :param float [params.shortLeverageRr]: *hedged mode only* set the leverage for short positions
4102
+ :returns dict: response from the exchange
4103
+ """
4104
+ # WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
4105
+ # AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
4106
+ if symbol is None:
4107
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
4108
+ if (leverage < -100) or (leverage > 100):
4109
+ raise BadRequest(self.id + ' setLeverage() leverage should be between -100 and 100')
4110
+ await self.load_markets()
4111
+ isHedged = self.safe_bool(params, 'hedged', False)
4112
+ longLeverageRr = self.safe_integer(params, 'longLeverageRr')
4113
+ shortLeverageRr = self.safe_integer(params, 'shortLeverageRr')
4114
+ market = self.market(symbol)
4115
+ request: dict = {
4116
+ 'symbol': market['id'],
4117
+ }
4118
+ response = None
4119
+ if market['settle'] == 'USDT':
4120
+ if not isHedged and longLeverageRr is None and shortLeverageRr is None:
4121
+ request['leverageRr'] = leverage
4122
+ else:
4123
+ longVar = longLeverageRr if (longLeverageRr is not None) else leverage
4124
+ shortVar = shortLeverageRr if (shortLeverageRr is not None) else leverage
4125
+ request['longLeverageRr'] = longVar
4126
+ request['shortLeverageRr'] = shortVar
4127
+ response = await self.privatePutGPositionsLeverage(self.extend(request, params))
4128
+ else:
4129
+ request['leverage'] = leverage
4130
+ response = await self.privatePutPositionsLeverage(self.extend(request, params))
4131
+ return response
4132
+
4133
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
4134
+ """
4135
+ transfer currency internally between wallets on the same account
4136
+ :param str code: unified currency code
4137
+ :param float amount: amount to transfer
4138
+ :param str fromAccount: account to transfer from
4139
+ :param str toAccount: account to transfer to
4140
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4141
+ :param str [params.bizType]: for transferring between main and sub-acounts either 'SPOT' or 'PERPETUAL' default is 'SPOT'
4142
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
4143
+ """
4144
+ await self.load_markets()
4145
+ currency = self.currency(code)
4146
+ accountsByType = self.safe_value(self.options, 'accountsByType', {})
4147
+ fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
4148
+ toId = self.safe_string(accountsByType, toAccount, toAccount)
4149
+ scaledAmmount = self.to_ev(amount, currency)
4150
+ direction = None
4151
+ transfer = None
4152
+ if fromId == 'spot' and toId == 'future':
4153
+ direction = 2
4154
+ elif fromId == 'future' and toId == 'spot':
4155
+ direction = 1
4156
+ if direction is not None:
4157
+ request: dict = {
4158
+ 'currency': currency['id'],
4159
+ 'moveOp': direction,
4160
+ 'amountEv': scaledAmmount,
4161
+ }
4162
+ response = await self.privatePostAssetsTransfer(self.extend(request, params))
4163
+ #
4164
+ # {
4165
+ # "code": "0",
4166
+ # "msg": "OK",
4167
+ # "data": {
4168
+ # "linkKey": "8564eba4-c9ec-49d6-9b8c-2ec5001a0fb9",
4169
+ # "userId": "4018340",
4170
+ # "currency": "USD",
4171
+ # "amountEv": "10",
4172
+ # "side": "2",
4173
+ # "status": "10"
4174
+ # }
4175
+ # }
4176
+ #
4177
+ data = self.safe_value(response, 'data', {})
4178
+ transfer = self.parse_transfer(data, currency)
4179
+ else: # sub account transfer
4180
+ request: dict = {
4181
+ 'fromUserId': fromId,
4182
+ 'toUserId': toId,
4183
+ 'amountEv': scaledAmmount,
4184
+ 'currency': currency['id'],
4185
+ 'bizType': self.safe_string(params, 'bizType', 'SPOT'),
4186
+ }
4187
+ response = await self.privatePostAssetsUniversalTransfer(self.extend(request, params))
4188
+ #
4189
+ # {
4190
+ # "code": "0",
4191
+ # "msg": "OK",
4192
+ # "data": "API-923db826-aaaa-aaaa-aaaa-4d98c3a7c9fd"
4193
+ # }
4194
+ #
4195
+ transfer = self.parse_transfer(response)
4196
+ transferOptions = self.safe_value(self.options, 'transfer', {})
4197
+ fillResponseFromRequest = self.safe_bool(transferOptions, 'fillResponseFromRequest', True)
4198
+ if fillResponseFromRequest:
4199
+ if transfer['fromAccount'] is None:
4200
+ transfer['fromAccount'] = fromAccount
4201
+ if transfer['toAccount'] is None:
4202
+ transfer['toAccount'] = toAccount
4203
+ if transfer['amount'] is None:
4204
+ transfer['amount'] = amount
4205
+ if transfer['currency'] is None:
4206
+ transfer['currency'] = code
4207
+ return transfer
4208
+
4209
+ async def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> TransferEntries:
4210
+ """
4211
+ fetch a history of internal transfers made on an account
4212
+ :param str code: unified currency code of the currency transferred
4213
+ :param int [since]: the earliest time in ms to fetch transfers for
4214
+ :param int [limit]: the maximum number of transfers structures to retrieve
4215
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4216
+ :returns dict[]: a list of `transfer structures <https://docs.ccxt.com/#/?id=transfer-structure>`
4217
+ """
4218
+ await self.load_markets()
4219
+ if code is None:
4220
+ raise ArgumentsRequired(self.id + ' fetchTransfers() requires a code argument')
4221
+ currency = self.currency(code)
4222
+ request: dict = {
4223
+ 'currency': currency['id'],
4224
+ }
4225
+ if since is not None:
4226
+ request['start'] = since
4227
+ if limit is not None:
4228
+ request['limit'] = limit
4229
+ response = await self.privateGetAssetsTransfer(self.extend(request, params))
4230
+ #
4231
+ # {
4232
+ # "code": 0,
4233
+ # "msg": "OK",
4234
+ # "data": {
4235
+ # "rows": [
4236
+ # {
4237
+ # "linkKey": "87c071a3-8628-4ac2-aca1-6ce0d1fad66c",
4238
+ # "userId": 4148428,
4239
+ # "currency": "BTC",
4240
+ # "amountEv": 67932,
4241
+ # "side": 2,
4242
+ # "status": 10,
4243
+ # "createTime": 1652832467000,
4244
+ # "bizType": 10
4245
+ # }
4246
+ # ]
4247
+ # }
4248
+ # }
4249
+ #
4250
+ data = self.safe_value(response, 'data', {})
4251
+ transfers = self.safe_list(data, 'rows', [])
4252
+ return self.parse_transfers(transfers, currency, since, limit)
4253
+
4254
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
4255
+ #
4256
+ # transfer
4257
+ #
4258
+ # {
4259
+ # "linkKey": "8564eba4-c9ec-49d6-9b8c-2ec5001a0fb9",
4260
+ # "userId": "4018340",
4261
+ # "currency": "USD",
4262
+ # "amountEv": "10",
4263
+ # "side": "2",
4264
+ # "status": "10"
4265
+ # }
4266
+ #
4267
+ # fetchTransfers
4268
+ #
4269
+ # {
4270
+ # "linkKey": "87c071a3-8628-4ac2-aca1-6ce0d1fad66c",
4271
+ # "userId": 4148428,
4272
+ # "currency": "BTC",
4273
+ # "amountEv": 67932,
4274
+ # "side": 2,
4275
+ # "status": 10,
4276
+ # "createTime": 1652832467000,
4277
+ # "bizType": 10
4278
+ # }
4279
+ #
4280
+ id = self.safe_string(transfer, 'linkKey')
4281
+ status = self.safe_string(transfer, 'status')
4282
+ amountEv = self.safe_string(transfer, 'amountEv')
4283
+ amountTransfered = self.from_ev(amountEv)
4284
+ currencyId = self.safe_string(transfer, 'currency')
4285
+ code = self.safe_currency_code(currencyId, currency)
4286
+ side = self.safe_integer(transfer, 'side')
4287
+ fromId = None
4288
+ toId = None
4289
+ if side == 1:
4290
+ fromId = 'swap'
4291
+ toId = 'spot'
4292
+ elif side == 2:
4293
+ fromId = 'spot'
4294
+ toId = 'swap'
4295
+ timestamp = self.safe_integer(transfer, 'createTime')
4296
+ return {
4297
+ 'info': transfer,
4298
+ 'id': id,
4299
+ 'timestamp': timestamp,
4300
+ 'datetime': self.iso8601(timestamp),
4301
+ 'currency': code,
4302
+ 'amount': amountTransfered,
4303
+ 'fromAccount': fromId,
4304
+ 'toAccount': toId,
4305
+ 'status': self.parse_transfer_status(status),
4306
+ }
4307
+
4308
+ def parse_transfer_status(self, status: Str) -> Str:
4309
+ statuses: dict = {
4310
+ '3': 'rejected', # 'Rejected',
4311
+ '6': 'canceled', # 'Got error and wait for recovery',
4312
+ '10': 'ok', # 'Success',
4313
+ '11': 'failed', # 'Failed',
4314
+ }
4315
+ return self.safe_string(statuses, status, status)
4316
+
4317
+ async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4318
+ """
4319
+ fetches historical funding rate prices
4320
+ :see: https://phemex-docs.github.io/#query-funding-rate-history-2
4321
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
4322
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
4323
+ :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
4324
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4325
+ :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)
4326
+ :param int [params.until]: timestamp in ms of the latest funding rate
4327
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
4328
+ """
4329
+ if symbol is None:
4330
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
4331
+ await self.load_markets()
4332
+ market = self.market(symbol)
4333
+ isUsdtSettled = market['settle'] == 'USDT'
4334
+ if not market['swap']:
4335
+ raise BadRequest(self.id + ' fetchFundingRateHistory() supports swap contracts only')
4336
+ paginate = False
4337
+ paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
4338
+ if paginate:
4339
+ return await self.fetch_paginated_call_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params, 100)
4340
+ customSymbol = None
4341
+ if isUsdtSettled:
4342
+ customSymbol = '.' + market['id'] + 'FR8H' # phemex requires a custom symbol for funding rate history
4343
+ else:
4344
+ customSymbol = '.' + market['baseId'] + 'FR8H'
4345
+ request: dict = {
4346
+ 'symbol': customSymbol,
4347
+ }
4348
+ if since is not None:
4349
+ request['start'] = since
4350
+ if limit is not None:
4351
+ request['limit'] = limit
4352
+ request, params = self.handle_until_option('end', request, params)
4353
+ response = None
4354
+ if isUsdtSettled:
4355
+ response = await self.v2GetApiDataPublicDataFundingRateHistory(self.extend(request, params))
4356
+ else:
4357
+ response = await self.v1GetApiDataPublicDataFundingRateHistory(self.extend(request, params))
4358
+ #
4359
+ # {
4360
+ # "code":"0",
4361
+ # "msg":"OK",
4362
+ # "data":{
4363
+ # "rows":[
4364
+ # {
4365
+ # "symbol":".BTCUSDTFR8H",
4366
+ # "fundingRate":"0.0001",
4367
+ # "fundingTime":"1682064000000",
4368
+ # "intervalSeconds":"28800"
4369
+ # }
4370
+ # ]
4371
+ # }
4372
+ # }
4373
+ #
4374
+ data = self.safe_value(response, 'data', {})
4375
+ rates = self.safe_value(data, 'rows')
4376
+ result = []
4377
+ for i in range(0, len(rates)):
4378
+ item = rates[i]
4379
+ timestamp = self.safe_integer(item, 'fundingTime')
4380
+ result.append({
4381
+ 'info': item,
4382
+ 'symbol': symbol,
4383
+ 'fundingRate': self.safe_number(item, 'fundingRate'),
4384
+ 'timestamp': timestamp,
4385
+ 'datetime': self.iso8601(timestamp),
4386
+ })
4387
+ sorted = self.sort_by(result, 'timestamp')
4388
+ return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
4389
+
4390
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
4391
+ """
4392
+ make a withdrawal
4393
+ :see: https://phemex-docs.github.io/#create-withdraw-request
4394
+ :param str code: unified currency code
4395
+ :param float amount: the amount to withdraw
4396
+ :param str address: the address to withdraw to
4397
+ :param str tag:
4398
+ :param dict [params]: extra parameters specific to the phemex api endpoint
4399
+ :param str [params.network]: unified network code
4400
+ :returns dict: a `transaction structure <https://github.com/ccxt/ccxt/wiki/Manual#transaction-structure>`
4401
+ """
4402
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
4403
+ await self.load_markets()
4404
+ self.check_address(address)
4405
+ currency = self.currency(code)
4406
+ networkCode = None
4407
+ networkCode, params = self.handle_network_code_and_params(params)
4408
+ networkId = None
4409
+ if networkCode is not None:
4410
+ networkId = self.network_code_to_id(networkCode)
4411
+ stableCoins = self.safe_value(self.options, 'stableCoins')
4412
+ if networkId is None:
4413
+ if not (self.in_array(code, stableCoins)):
4414
+ networkId = currency['id']
4415
+ else:
4416
+ raise ArgumentsRequired(self.id + ' withdraw() requires an extra argument params["network"]')
4417
+ request: dict = {
4418
+ 'currency': currency['id'],
4419
+ 'address': address,
4420
+ 'amount': amount,
4421
+ 'chainName': networkId.upper(),
4422
+ }
4423
+ if tag is not None:
4424
+ request['addressTag'] = tag
4425
+ response = await self.privatePostPhemexWithdrawWalletsApiCreateWithdraw(self.extend(request, params))
4426
+ #
4427
+ # {
4428
+ # "code": 0,
4429
+ # "msg": "OK",
4430
+ # "data": {
4431
+ # "id": "10000001",
4432
+ # "freezeId": null,
4433
+ # "address": "44exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
4434
+ # "amountRv": "100",
4435
+ # "chainCode": "11",
4436
+ # "chainName": "TRX",
4437
+ # "currency": "USDT",
4438
+ # "currencyCode": 3,
4439
+ # "email": "abc@gmail.com",
4440
+ # "expiredTime": "0",
4441
+ # "feeRv": "1",
4442
+ # "nickName": null,
4443
+ # "phone": null,
4444
+ # "rejectReason": "",
4445
+ # "submitedAt": "1670000000000",
4446
+ # "submittedAt": "1670000000000",
4447
+ # "txHash": null,
4448
+ # "userId": "10000001",
4449
+ # "status": "Success"
4450
+ # }
4451
+ # }
4452
+ #
4453
+ data = self.safe_dict(response, 'data', {})
4454
+ return self.parse_transaction(data, currency)
4455
+
4456
+ def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
4457
+ if response is None:
4458
+ return None # fallback to default error handler
4459
+ #
4460
+ # {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
4461
+ # {"code":412,"msg":"Missing parameter - resolution","data":null}
4462
+ # {"code":412,"msg":"Missing parameter - to","data":null}
4463
+ # {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
4464
+ #
4465
+ error = self.safe_value(response, 'error', response)
4466
+ errorCode = self.safe_string(error, 'code')
4467
+ message = self.safe_string(error, 'msg')
4468
+ if (errorCode is not None) and (errorCode != '0'):
4469
+ feedback = self.id + ' ' + body
4470
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
4471
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
4472
+ raise ExchangeError(feedback) # unknown message
4473
+ return None