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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. ccxt/__init__.py +358 -0
  2. ccxt/abantether.py +316 -0
  3. ccxt/abstract/__init__.py +0 -0
  4. ccxt/abstract/abantether.py +5 -0
  5. ccxt/abstract/ace.py +15 -0
  6. ccxt/abstract/afratether.py +6 -0
  7. ccxt/abstract/alpaca.py +70 -0
  8. ccxt/abstract/arzinja.py +5 -0
  9. ccxt/abstract/arzplus.py +7 -0
  10. ccxt/abstract/ascendex.py +77 -0
  11. ccxt/abstract/bequant.py +115 -0
  12. ccxt/abstract/bigone.py +45 -0
  13. ccxt/abstract/binance.py +712 -0
  14. ccxt/abstract/binancecoinm.py +712 -0
  15. ccxt/abstract/binanceus.py +764 -0
  16. ccxt/abstract/binanceusdm.py +712 -0
  17. ccxt/abstract/bingx.py +113 -0
  18. ccxt/abstract/bit2c.py +27 -0
  19. ccxt/abstract/bitbank.py +27 -0
  20. ccxt/abstract/bitbay.py +53 -0
  21. ccxt/abstract/bitbns.py +40 -0
  22. ccxt/abstract/bitcoincom.py +115 -0
  23. ccxt/abstract/bitfinex.py +69 -0
  24. ccxt/abstract/bitfinex2.py +139 -0
  25. ccxt/abstract/bitflyer.py +38 -0
  26. ccxt/abstract/bitget.py +508 -0
  27. ccxt/abstract/bithumb.py +32 -0
  28. ccxt/abstract/bitimen.py +7 -0
  29. ccxt/abstract/bitir.py +7 -0
  30. ccxt/abstract/bitmart.py +99 -0
  31. ccxt/abstract/bitmex.py +97 -0
  32. ccxt/abstract/bitopro.py +29 -0
  33. ccxt/abstract/bitpanda.py +35 -0
  34. ccxt/abstract/bitpin.py +7 -0
  35. ccxt/abstract/bitrue.py +72 -0
  36. ccxt/abstract/bitso.py +43 -0
  37. ccxt/abstract/bitstamp.py +258 -0
  38. ccxt/abstract/bitteam.py +29 -0
  39. ccxt/abstract/bitvavo.py +27 -0
  40. ccxt/abstract/bl3p.py +19 -0
  41. ccxt/abstract/blockchaincom.py +28 -0
  42. ccxt/abstract/blofin.py +37 -0
  43. ccxt/abstract/btcalpha.py +18 -0
  44. ccxt/abstract/btcbox.py +13 -0
  45. ccxt/abstract/btcmarkets.py +39 -0
  46. ccxt/abstract/btcturk.py +20 -0
  47. ccxt/abstract/bybit.py +298 -0
  48. ccxt/abstract/cex.py +33 -0
  49. ccxt/abstract/coinbase.py +94 -0
  50. ccxt/abstract/coinbaseadvanced.py +94 -0
  51. ccxt/abstract/coinbaseexchange.py +67 -0
  52. ccxt/abstract/coinbaseinternational.py +39 -0
  53. ccxt/abstract/coincatch.py +94 -0
  54. ccxt/abstract/coincheck.py +33 -0
  55. ccxt/abstract/coinex.py +237 -0
  56. ccxt/abstract/coinlist.py +54 -0
  57. ccxt/abstract/coinmate.py +62 -0
  58. ccxt/abstract/coinmetro.py +34 -0
  59. ccxt/abstract/coinone.py +67 -0
  60. ccxt/abstract/coinsph.py +54 -0
  61. ccxt/abstract/coinspot.py +28 -0
  62. ccxt/abstract/cryptocom.py +107 -0
  63. ccxt/abstract/currencycom.py +68 -0
  64. ccxt/abstract/delta.py +50 -0
  65. ccxt/abstract/deribit.py +125 -0
  66. ccxt/abstract/digifinex.py +91 -0
  67. ccxt/abstract/eterex.py +5 -0
  68. ccxt/abstract/excoino.py +7 -0
  69. ccxt/abstract/exir.py +8 -0
  70. ccxt/abstract/exmo.py +55 -0
  71. ccxt/abstract/exnovin.py +6 -0
  72. ccxt/abstract/farhadexchange.py +5 -0
  73. ccxt/abstract/fmfwio.py +115 -0
  74. ccxt/abstract/gate.py +265 -0
  75. ccxt/abstract/gateio.py +265 -0
  76. ccxt/abstract/gemini.py +58 -0
  77. ccxt/abstract/hashkey.py +67 -0
  78. ccxt/abstract/hitbtc.py +115 -0
  79. ccxt/abstract/hitbtc3.py +115 -0
  80. ccxt/abstract/hitobit.py +8 -0
  81. ccxt/abstract/hollaex.py +33 -0
  82. ccxt/abstract/htx.py +548 -0
  83. ccxt/abstract/huobi.py +548 -0
  84. ccxt/abstract/huobijp.py +114 -0
  85. ccxt/abstract/hyperliquid.py +6 -0
  86. ccxt/abstract/idex.py +26 -0
  87. ccxt/abstract/independentreserve.py +37 -0
  88. ccxt/abstract/indodax.py +26 -0
  89. ccxt/abstract/jibitex.py +7 -0
  90. ccxt/abstract/kraken.py +57 -0
  91. ccxt/abstract/krakenfutures.py +38 -0
  92. ccxt/abstract/kucoin.py +214 -0
  93. ccxt/abstract/kucoinfutures.py +233 -0
  94. ccxt/abstract/kuna.py +182 -0
  95. ccxt/abstract/latoken.py +56 -0
  96. ccxt/abstract/lbank.py +61 -0
  97. ccxt/abstract/luno.py +37 -0
  98. ccxt/abstract/lykke.py +29 -0
  99. ccxt/abstract/mercado.py +25 -0
  100. ccxt/abstract/mexc.py +178 -0
  101. ccxt/abstract/ndax.py +97 -0
  102. ccxt/abstract/nobitex.py +7 -0
  103. ccxt/abstract/novadax.py +29 -0
  104. ccxt/abstract/oceanex.py +22 -0
  105. ccxt/abstract/okcoin.py +74 -0
  106. ccxt/abstract/okexchange.py +8 -0
  107. ccxt/abstract/okx.py +324 -0
  108. ccxt/abstract/ompfinex.py +7 -0
  109. ccxt/abstract/onetrading.py +35 -0
  110. ccxt/abstract/oxfun.py +34 -0
  111. ccxt/abstract/p2b.py +22 -0
  112. ccxt/abstract/paradex.py +40 -0
  113. ccxt/abstract/paymium.py +28 -0
  114. ccxt/abstract/phemex.py +115 -0
  115. ccxt/abstract/poloniex.py +69 -0
  116. ccxt/abstract/poloniexfutures.py +48 -0
  117. ccxt/abstract/probit.py +23 -0
  118. ccxt/abstract/ramzinex.py +7 -0
  119. ccxt/abstract/sarmayex.py +5 -0
  120. ccxt/abstract/sarrafex.py +7 -0
  121. ccxt/abstract/tabdeal.py +7 -0
  122. ccxt/abstract/tetherland.py +5 -0
  123. ccxt/abstract/timex.py +62 -0
  124. ccxt/abstract/tokocrypto.py +37 -0
  125. ccxt/abstract/tradeogre.py +16 -0
  126. ccxt/abstract/twox.py +5 -0
  127. ccxt/abstract/ubitex.py +7 -0
  128. ccxt/abstract/upbit.py +38 -0
  129. ccxt/abstract/vertex.py +19 -0
  130. ccxt/abstract/wallex.py +8 -0
  131. ccxt/abstract/wavesexchange.py +154 -0
  132. ccxt/abstract/wazirx.py +30 -0
  133. ccxt/abstract/whitebit.py +98 -0
  134. ccxt/abstract/woo.py +83 -0
  135. ccxt/abstract/woofipro.py +119 -0
  136. ccxt/abstract/xt.py +152 -0
  137. ccxt/abstract/yobit.py +16 -0
  138. ccxt/abstract/zaif.py +38 -0
  139. ccxt/abstract/zonda.py +53 -0
  140. ccxt/ace.py +1012 -0
  141. ccxt/afratether.py +293 -0
  142. ccxt/alpaca.py +1083 -0
  143. ccxt/arzinja.py +285 -0
  144. ccxt/arzplus.py +412 -0
  145. ccxt/ascendex.py +3330 -0
  146. ccxt/async_support/__init__.py +337 -0
  147. ccxt/async_support/abantether.py +316 -0
  148. ccxt/async_support/ace.py +1012 -0
  149. ccxt/async_support/afratether.py +293 -0
  150. ccxt/async_support/alpaca.py +1083 -0
  151. ccxt/async_support/arzinja.py +285 -0
  152. ccxt/async_support/arzplus.py +412 -0
  153. ccxt/async_support/ascendex.py +3330 -0
  154. ccxt/async_support/base/__init__.py +1 -0
  155. ccxt/async_support/base/exchange.py +1966 -0
  156. ccxt/async_support/base/throttler.py +50 -0
  157. ccxt/async_support/base/ws/__init__.py +38 -0
  158. ccxt/async_support/base/ws/aiohttp_client.py +125 -0
  159. ccxt/async_support/base/ws/cache.py +212 -0
  160. ccxt/async_support/base/ws/client.py +193 -0
  161. ccxt/async_support/base/ws/fast_client.py +96 -0
  162. ccxt/async_support/base/ws/functions.py +59 -0
  163. ccxt/async_support/base/ws/future.py +58 -0
  164. ccxt/async_support/base/ws/order_book.py +78 -0
  165. ccxt/async_support/base/ws/order_book_side.py +174 -0
  166. ccxt/async_support/bequant.py +33 -0
  167. ccxt/async_support/bigone.py +2113 -0
  168. ccxt/async_support/binance.py +12234 -0
  169. ccxt/async_support/binancecoinm.py +45 -0
  170. ccxt/async_support/binanceus.py +211 -0
  171. ccxt/async_support/binanceusdm.py +58 -0
  172. ccxt/async_support/bingx.py +4325 -0
  173. ccxt/async_support/bit2c.py +866 -0
  174. ccxt/async_support/bitbank.py +1001 -0
  175. ccxt/async_support/bitbay.py +17 -0
  176. ccxt/async_support/bitbns.py +1154 -0
  177. ccxt/async_support/bitcoincom.py +17 -0
  178. ccxt/async_support/bitfinex.py +1617 -0
  179. ccxt/async_support/bitfinex2.py +3552 -0
  180. ccxt/async_support/bitflyer.py +995 -0
  181. ccxt/async_support/bitget.py +8273 -0
  182. ccxt/async_support/bithumb.py +1061 -0
  183. ccxt/async_support/bitimen.py +401 -0
  184. ccxt/async_support/bitir.py +490 -0
  185. ccxt/async_support/bitmart.py +4415 -0
  186. ccxt/async_support/bitmex.py +2756 -0
  187. ccxt/async_support/bitopro.py +1630 -0
  188. ccxt/async_support/bitpanda.py +16 -0
  189. ccxt/async_support/bitpin.py +454 -0
  190. ccxt/async_support/bitrue.py +3027 -0
  191. ccxt/async_support/bitso.py +1670 -0
  192. ccxt/async_support/bitstamp.py +2203 -0
  193. ccxt/async_support/bitteam.py +2239 -0
  194. ccxt/async_support/bitvavo.py +1968 -0
  195. ccxt/async_support/bl3p.py +485 -0
  196. ccxt/async_support/blockchaincom.py +1104 -0
  197. ccxt/async_support/blofin.py +2066 -0
  198. ccxt/async_support/btcalpha.py +891 -0
  199. ccxt/async_support/btcbox.py +544 -0
  200. ccxt/async_support/btcmarkets.py +1221 -0
  201. ccxt/async_support/btcturk.py +911 -0
  202. ccxt/async_support/bybit.py +8159 -0
  203. ccxt/async_support/cex.py +1605 -0
  204. ccxt/async_support/coinbase.py +4475 -0
  205. ccxt/async_support/coinbaseadvanced.py +17 -0
  206. ccxt/async_support/coinbaseexchange.py +1734 -0
  207. ccxt/async_support/coinbaseinternational.py +1899 -0
  208. ccxt/async_support/coincatch.py +5069 -0
  209. ccxt/async_support/coincheck.py +815 -0
  210. ccxt/async_support/coinex.py +5526 -0
  211. ccxt/async_support/coinlist.py +2243 -0
  212. ccxt/async_support/coinmate.py +1067 -0
  213. ccxt/async_support/coinmetro.py +1797 -0
  214. ccxt/async_support/coinone.py +1127 -0
  215. ccxt/async_support/coinsph.py +1850 -0
  216. ccxt/async_support/coinspot.py +534 -0
  217. ccxt/async_support/cryptocom.py +2822 -0
  218. ccxt/async_support/currencycom.py +1950 -0
  219. ccxt/async_support/delta.py +3376 -0
  220. ccxt/async_support/deribit.py +3437 -0
  221. ccxt/async_support/digifinex.py +3960 -0
  222. ccxt/async_support/eterex.py +286 -0
  223. ccxt/async_support/excoino.py +399 -0
  224. ccxt/async_support/exir.py +375 -0
  225. ccxt/async_support/exmo.py +2462 -0
  226. ccxt/async_support/exnovin.py +360 -0
  227. ccxt/async_support/farhadexchange.py +266 -0
  228. ccxt/async_support/fmfwio.py +34 -0
  229. ccxt/async_support/gate.py +6976 -0
  230. ccxt/async_support/gateio.py +16 -0
  231. ccxt/async_support/gemini.py +1825 -0
  232. ccxt/async_support/hashkey.py +4150 -0
  233. ccxt/async_support/hitbtc.py +3423 -0
  234. ccxt/async_support/hitbtc3.py +16 -0
  235. ccxt/async_support/hitobit.py +391 -0
  236. ccxt/async_support/hollaex.py +1813 -0
  237. ccxt/async_support/htx.py +8506 -0
  238. ccxt/async_support/huobi.py +16 -0
  239. ccxt/async_support/huobijp.py +1801 -0
  240. ccxt/async_support/hyperliquid.py +2431 -0
  241. ccxt/async_support/idex.py +1766 -0
  242. ccxt/async_support/independentreserve.py +784 -0
  243. ccxt/async_support/indodax.py +1247 -0
  244. ccxt/async_support/jibitex.py +395 -0
  245. ccxt/async_support/kraken.py +2894 -0
  246. ccxt/async_support/krakenfutures.py +2601 -0
  247. ccxt/async_support/kucoin.py +4602 -0
  248. ccxt/async_support/kucoinfutures.py +2698 -0
  249. ccxt/async_support/kuna.py +1841 -0
  250. ccxt/async_support/latoken.py +1664 -0
  251. ccxt/async_support/lbank.py +2683 -0
  252. ccxt/async_support/luno.py +1067 -0
  253. ccxt/async_support/lykke.py +1270 -0
  254. ccxt/async_support/mercado.py +842 -0
  255. ccxt/async_support/mexc.py +5369 -0
  256. ccxt/async_support/ndax.py +2354 -0
  257. ccxt/async_support/nobitex.py +419 -0
  258. ccxt/async_support/novadax.py +1484 -0
  259. ccxt/async_support/oceanex.py +903 -0
  260. ccxt/async_support/okcoin.py +2936 -0
  261. ccxt/async_support/okexchange.py +349 -0
  262. ccxt/async_support/okx.py +7827 -0
  263. ccxt/async_support/ompfinex.py +472 -0
  264. ccxt/async_support/onetrading.py +1911 -0
  265. ccxt/async_support/oxfun.py +2773 -0
  266. ccxt/async_support/p2b.py +1194 -0
  267. ccxt/async_support/paradex.py +2015 -0
  268. ccxt/async_support/paymium.py +564 -0
  269. ccxt/async_support/phemex.py +4473 -0
  270. ccxt/async_support/poloniex.py +2232 -0
  271. ccxt/async_support/poloniexfutures.py +1717 -0
  272. ccxt/async_support/probit.py +1734 -0
  273. ccxt/async_support/ramzinex.py +476 -0
  274. ccxt/async_support/sarmayex.py +357 -0
  275. ccxt/async_support/sarrafex.py +478 -0
  276. ccxt/async_support/tabdeal.py +364 -0
  277. ccxt/async_support/tetherland.py +349 -0
  278. ccxt/async_support/timex.py +1593 -0
  279. ccxt/async_support/tokocrypto.py +2405 -0
  280. ccxt/async_support/tradeogre.py +608 -0
  281. ccxt/async_support/twox.py +326 -0
  282. ccxt/async_support/ubitex.py +409 -0
  283. ccxt/async_support/upbit.py +1833 -0
  284. ccxt/async_support/vertex.py +2922 -0
  285. ccxt/async_support/wallex.py +445 -0
  286. ccxt/async_support/wavesexchange.py +2473 -0
  287. ccxt/async_support/wazirx.py +1224 -0
  288. ccxt/async_support/whitebit.py +2469 -0
  289. ccxt/async_support/woo.py +3114 -0
  290. ccxt/async_support/woofipro.py +2533 -0
  291. ccxt/async_support/xt.py +4454 -0
  292. ccxt/async_support/yobit.py +1283 -0
  293. ccxt/async_support/zaif.py +725 -0
  294. ccxt/async_support/zonda.py +1828 -0
  295. ccxt/base/__init__.py +27 -0
  296. ccxt/base/decimal_to_precision.py +174 -0
  297. ccxt/base/errors.py +242 -0
  298. ccxt/base/exchange.py +5941 -0
  299. ccxt/base/precise.py +287 -0
  300. ccxt/base/types.py +502 -0
  301. ccxt/bequant.py +33 -0
  302. ccxt/bigone.py +2112 -0
  303. ccxt/binance.py +12233 -0
  304. ccxt/binancecoinm.py +45 -0
  305. ccxt/binanceus.py +211 -0
  306. ccxt/binanceusdm.py +58 -0
  307. ccxt/bingx.py +4324 -0
  308. ccxt/bit2c.py +866 -0
  309. ccxt/bitbank.py +1001 -0
  310. ccxt/bitbay.py +17 -0
  311. ccxt/bitbns.py +1154 -0
  312. ccxt/bitcoincom.py +17 -0
  313. ccxt/bitfinex.py +1617 -0
  314. ccxt/bitfinex2.py +3552 -0
  315. ccxt/bitflyer.py +995 -0
  316. ccxt/bitget.py +8272 -0
  317. ccxt/bithumb.py +1061 -0
  318. ccxt/bitimen.py +401 -0
  319. ccxt/bitir.py +490 -0
  320. ccxt/bitmart.py +4415 -0
  321. ccxt/bitmex.py +2756 -0
  322. ccxt/bitopro.py +1630 -0
  323. ccxt/bitpanda.py +16 -0
  324. ccxt/bitpin.py +454 -0
  325. ccxt/bitrue.py +3026 -0
  326. ccxt/bitso.py +1670 -0
  327. ccxt/bitstamp.py +2203 -0
  328. ccxt/bitteam.py +2239 -0
  329. ccxt/bitvavo.py +1968 -0
  330. ccxt/bl3p.py +485 -0
  331. ccxt/blockchaincom.py +1104 -0
  332. ccxt/blofin.py +2066 -0
  333. ccxt/btcalpha.py +891 -0
  334. ccxt/btcbox.py +544 -0
  335. ccxt/btcmarkets.py +1221 -0
  336. ccxt/btcturk.py +911 -0
  337. ccxt/bybit.py +8158 -0
  338. ccxt/cex.py +1605 -0
  339. ccxt/coinbase.py +4474 -0
  340. ccxt/coinbaseadvanced.py +17 -0
  341. ccxt/coinbaseexchange.py +1734 -0
  342. ccxt/coinbaseinternational.py +1899 -0
  343. ccxt/coincatch.py +5069 -0
  344. ccxt/coincheck.py +815 -0
  345. ccxt/coinex.py +5525 -0
  346. ccxt/coinlist.py +2243 -0
  347. ccxt/coinmate.py +1067 -0
  348. ccxt/coinmetro.py +1797 -0
  349. ccxt/coinone.py +1127 -0
  350. ccxt/coinsph.py +1850 -0
  351. ccxt/coinspot.py +534 -0
  352. ccxt/cryptocom.py +2822 -0
  353. ccxt/currencycom.py +1950 -0
  354. ccxt/delta.py +3376 -0
  355. ccxt/deribit.py +3437 -0
  356. ccxt/digifinex.py +3959 -0
  357. ccxt/eterex.py +286 -0
  358. ccxt/excoino.py +399 -0
  359. ccxt/exir.py +375 -0
  360. ccxt/exmo.py +2462 -0
  361. ccxt/exnovin.py +360 -0
  362. ccxt/farhadexchange.py +266 -0
  363. ccxt/fmfwio.py +34 -0
  364. ccxt/gate.py +6975 -0
  365. ccxt/gateio.py +16 -0
  366. ccxt/gemini.py +1824 -0
  367. ccxt/hashkey.py +4150 -0
  368. ccxt/hitbtc.py +3423 -0
  369. ccxt/hitbtc3.py +16 -0
  370. ccxt/hitobit.py +391 -0
  371. ccxt/hollaex.py +1813 -0
  372. ccxt/htx.py +8505 -0
  373. ccxt/huobi.py +16 -0
  374. ccxt/huobijp.py +1801 -0
  375. ccxt/hyperliquid.py +2430 -0
  376. ccxt/idex.py +1766 -0
  377. ccxt/independentreserve.py +784 -0
  378. ccxt/indodax.py +1247 -0
  379. ccxt/jibitex.py +395 -0
  380. ccxt/kraken.py +2894 -0
  381. ccxt/krakenfutures.py +2601 -0
  382. ccxt/kucoin.py +4601 -0
  383. ccxt/kucoinfutures.py +2698 -0
  384. ccxt/kuna.py +1841 -0
  385. ccxt/latoken.py +1664 -0
  386. ccxt/lbank.py +2682 -0
  387. ccxt/luno.py +1067 -0
  388. ccxt/lykke.py +1270 -0
  389. ccxt/mercado.py +842 -0
  390. ccxt/mexc.py +5369 -0
  391. ccxt/ndax.py +2354 -0
  392. ccxt/nobitex.py +419 -0
  393. ccxt/novadax.py +1484 -0
  394. ccxt/oceanex.py +903 -0
  395. ccxt/okcoin.py +2936 -0
  396. ccxt/okexchange.py +349 -0
  397. ccxt/okx.py +7826 -0
  398. ccxt/ompfinex.py +472 -0
  399. ccxt/onetrading.py +1911 -0
  400. ccxt/oxfun.py +2772 -0
  401. ccxt/p2b.py +1194 -0
  402. ccxt/paradex.py +2015 -0
  403. ccxt/paymium.py +564 -0
  404. ccxt/phemex.py +4473 -0
  405. ccxt/poloniex.py +2232 -0
  406. ccxt/poloniexfutures.py +1717 -0
  407. ccxt/pro/__init__.py +149 -0
  408. ccxt/pro/alpaca.py +685 -0
  409. ccxt/pro/ascendex.py +916 -0
  410. ccxt/pro/bequant.py +38 -0
  411. ccxt/pro/binance.py +3488 -0
  412. ccxt/pro/binancecoinm.py +28 -0
  413. ccxt/pro/binanceus.py +48 -0
  414. ccxt/pro/binanceusdm.py +31 -0
  415. ccxt/pro/bingx.py +1264 -0
  416. ccxt/pro/bitcoincom.py +34 -0
  417. ccxt/pro/bitfinex.py +621 -0
  418. ccxt/pro/bitfinex2.py +1083 -0
  419. ccxt/pro/bitget.py +1692 -0
  420. ccxt/pro/bithumb.py +368 -0
  421. ccxt/pro/bitmart.py +1449 -0
  422. ccxt/pro/bitmex.py +1656 -0
  423. ccxt/pro/bitopro.py +445 -0
  424. ccxt/pro/bitpanda.py +15 -0
  425. ccxt/pro/bitrue.py +447 -0
  426. ccxt/pro/bitstamp.py +522 -0
  427. ccxt/pro/bitvavo.py +1270 -0
  428. ccxt/pro/blockchaincom.py +738 -0
  429. ccxt/pro/blofin.py +692 -0
  430. ccxt/pro/bybit.py +2000 -0
  431. ccxt/pro/cex.py +1440 -0
  432. ccxt/pro/coinbase.py +678 -0
  433. ccxt/pro/coinbaseadvanced.py +16 -0
  434. ccxt/pro/coinbaseexchange.py +895 -0
  435. ccxt/pro/coinbaseinternational.py +620 -0
  436. ccxt/pro/coincatch.py +1464 -0
  437. ccxt/pro/coincheck.py +199 -0
  438. ccxt/pro/coinex.py +1061 -0
  439. ccxt/pro/coinone.py +395 -0
  440. ccxt/pro/cryptocom.py +947 -0
  441. ccxt/pro/currencycom.py +536 -0
  442. ccxt/pro/deribit.py +892 -0
  443. ccxt/pro/exmo.py +629 -0
  444. ccxt/pro/gate.py +1416 -0
  445. ccxt/pro/gateio.py +15 -0
  446. ccxt/pro/gemini.py +865 -0
  447. ccxt/pro/hashkey.py +802 -0
  448. ccxt/pro/hitbtc.py +1216 -0
  449. ccxt/pro/hollaex.py +563 -0
  450. ccxt/pro/htx.py +2215 -0
  451. ccxt/pro/huobi.py +15 -0
  452. ccxt/pro/huobijp.py +570 -0
  453. ccxt/pro/hyperliquid.py +525 -0
  454. ccxt/pro/idex.py +672 -0
  455. ccxt/pro/independentreserve.py +270 -0
  456. ccxt/pro/kraken.py +1356 -0
  457. ccxt/pro/krakenfutures.py +1492 -0
  458. ccxt/pro/kucoin.py +1133 -0
  459. ccxt/pro/kucoinfutures.py +1081 -0
  460. ccxt/pro/lbank.py +843 -0
  461. ccxt/pro/luno.py +303 -0
  462. ccxt/pro/mexc.py +1122 -0
  463. ccxt/pro/ndax.py +506 -0
  464. ccxt/pro/okcoin.py +698 -0
  465. ccxt/pro/okx.py +1851 -0
  466. ccxt/pro/onetrading.py +1275 -0
  467. ccxt/pro/oxfun.py +950 -0
  468. ccxt/pro/p2b.py +419 -0
  469. ccxt/pro/paradex.py +352 -0
  470. ccxt/pro/phemex.py +1441 -0
  471. ccxt/pro/poloniex.py +1166 -0
  472. ccxt/pro/poloniexfutures.py +990 -0
  473. ccxt/pro/probit.py +551 -0
  474. ccxt/pro/upbit.py +520 -0
  475. ccxt/pro/vertex.py +943 -0
  476. ccxt/pro/wazirx.py +749 -0
  477. ccxt/pro/whitebit.py +864 -0
  478. ccxt/pro/woo.py +1078 -0
  479. ccxt/pro/woofipro.py +1183 -0
  480. ccxt/pro/xt.py +1067 -0
  481. ccxt/probit.py +1734 -0
  482. ccxt/ramzinex.py +476 -0
  483. ccxt/sarmayex.py +357 -0
  484. ccxt/sarrafex.py +478 -0
  485. ccxt/static_dependencies/__init__.py +1 -0
  486. ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  487. ccxt/static_dependencies/ecdsa/_version.py +520 -0
  488. ccxt/static_dependencies/ecdsa/curves.py +56 -0
  489. ccxt/static_dependencies/ecdsa/der.py +221 -0
  490. ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  491. ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  492. ccxt/static_dependencies/ecdsa/keys.py +332 -0
  493. ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  494. ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  495. ccxt/static_dependencies/ecdsa/util.py +266 -0
  496. ccxt/static_dependencies/ethereum/__init__.py +7 -0
  497. ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  498. ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  499. ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  500. ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  501. ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  502. ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  503. ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  504. ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  505. ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  506. ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  507. ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  508. ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  509. ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  510. ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  511. ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  512. ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  513. ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  514. ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  515. ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  516. ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  517. ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  518. ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  519. ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  520. ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  521. ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  522. ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  523. ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  524. ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  525. ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  526. ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  527. ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  528. ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  529. ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  530. ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  531. ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  532. ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  533. ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  534. ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  535. ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  536. ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  537. ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  538. ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  539. ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  540. ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  541. ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  542. ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  543. ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  544. ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  545. ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  546. ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  547. ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  548. ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  549. ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  550. ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  551. ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  552. ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  553. ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  554. ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  555. ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  556. ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  557. ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  558. ccxt/static_dependencies/keccak/__init__.py +3 -0
  559. ccxt/static_dependencies/keccak/keccak.py +197 -0
  560. ccxt/static_dependencies/lark/__init__.py +38 -0
  561. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  562. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  563. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  564. ccxt/static_dependencies/lark/common.py +86 -0
  565. ccxt/static_dependencies/lark/exceptions.py +292 -0
  566. ccxt/static_dependencies/lark/grammar.py +130 -0
  567. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  568. ccxt/static_dependencies/lark/indenter.py +143 -0
  569. ccxt/static_dependencies/lark/lark.py +658 -0
  570. ccxt/static_dependencies/lark/lexer.py +678 -0
  571. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  572. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  573. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  574. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  575. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  576. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  577. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  578. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  579. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  580. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  581. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  582. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  583. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  584. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  585. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  586. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  587. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  588. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  589. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  590. ccxt/static_dependencies/lark/tree.py +267 -0
  591. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  592. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  593. ccxt/static_dependencies/lark/utils.py +343 -0
  594. ccxt/static_dependencies/lark/visitors.py +596 -0
  595. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  596. ccxt/static_dependencies/marshmallow/base.py +65 -0
  597. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  598. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  599. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  600. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  601. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  602. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  603. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  604. ccxt/static_dependencies/marshmallow/types.py +12 -0
  605. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  606. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  607. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  608. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  609. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  610. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  611. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  612. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  613. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  614. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  615. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  616. ccxt/static_dependencies/msgpack/__init__.py +55 -0
  617. ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  618. ccxt/static_dependencies/msgpack/ext.py +168 -0
  619. ccxt/static_dependencies/msgpack/fallback.py +951 -0
  620. ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  621. ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  622. ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  623. ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  624. ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  625. ccxt/static_dependencies/parsimonious/utils.py +40 -0
  626. ccxt/static_dependencies/starknet/__init__.py +0 -0
  627. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  628. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  629. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  630. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  631. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  632. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  633. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  634. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  635. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  636. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  637. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  638. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  639. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  640. ccxt/static_dependencies/starknet/common.py +15 -0
  641. ccxt/static_dependencies/starknet/constants.py +39 -0
  642. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  643. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  644. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  645. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  646. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  647. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  648. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  649. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  650. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  651. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  652. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  653. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  654. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  655. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  656. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  657. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  658. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  659. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  660. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  661. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  662. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  663. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  664. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  665. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  666. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  667. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  668. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  669. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  670. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  671. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  672. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  673. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  674. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  675. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  676. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  677. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  678. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  679. ccxt/static_dependencies/starkware/__init__.py +0 -0
  680. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  681. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  682. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  683. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  684. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  685. ccxt/static_dependencies/sympy/__init__.py +0 -0
  686. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  687. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  688. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  689. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  690. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  691. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  692. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  693. ccxt/static_dependencies/toolz/__init__.py +26 -0
  694. ccxt/static_dependencies/toolz/_signatures.py +784 -0
  695. ccxt/static_dependencies/toolz/_version.py +520 -0
  696. ccxt/static_dependencies/toolz/compatibility.py +30 -0
  697. ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  698. ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  699. ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  700. ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  701. ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  702. ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  703. ccxt/static_dependencies/toolz/recipes.py +46 -0
  704. ccxt/static_dependencies/toolz/utils.py +9 -0
  705. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  706. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  707. ccxt/tabdeal.py +364 -0
  708. ccxt/test/__init__.py +3 -0
  709. ccxt/test/base/__init__.py +29 -0
  710. ccxt/test/base/test_account.py +26 -0
  711. ccxt/test/base/test_balance.py +56 -0
  712. ccxt/test/base/test_borrow_interest.py +35 -0
  713. ccxt/test/base/test_borrow_rate.py +32 -0
  714. ccxt/test/base/test_calculate_fee.py +51 -0
  715. ccxt/test/base/test_crypto.py +127 -0
  716. ccxt/test/base/test_currency.py +76 -0
  717. ccxt/test/base/test_datetime.py +109 -0
  718. ccxt/test/base/test_decimal_to_precision.py +392 -0
  719. ccxt/test/base/test_deep_extend.py +68 -0
  720. ccxt/test/base/test_deposit_withdrawal.py +50 -0
  721. ccxt/test/base/test_exchange_datetime_functions.py +76 -0
  722. ccxt/test/base/test_funding_rate_history.py +29 -0
  723. ccxt/test/base/test_last_price.py +31 -0
  724. ccxt/test/base/test_ledger_entry.py +45 -0
  725. ccxt/test/base/test_ledger_item.py +48 -0
  726. ccxt/test/base/test_leverage_tier.py +33 -0
  727. ccxt/test/base/test_liquidation.py +50 -0
  728. ccxt/test/base/test_margin_mode.py +24 -0
  729. ccxt/test/base/test_margin_modification.py +35 -0
  730. ccxt/test/base/test_market.py +193 -0
  731. ccxt/test/base/test_number.py +411 -0
  732. ccxt/test/base/test_ohlcv.py +33 -0
  733. ccxt/test/base/test_open_interest.py +32 -0
  734. ccxt/test/base/test_order.py +64 -0
  735. ccxt/test/base/test_order_book.py +69 -0
  736. ccxt/test/base/test_position.py +60 -0
  737. ccxt/test/base/test_shared_methods.py +353 -0
  738. ccxt/test/base/test_status.py +24 -0
  739. ccxt/test/base/test_throttle.py +126 -0
  740. ccxt/test/base/test_ticker.py +92 -0
  741. ccxt/test/base/test_trade.py +47 -0
  742. ccxt/test/base/test_trading_fee.py +26 -0
  743. ccxt/test/base/test_transaction.py +39 -0
  744. ccxt/test/test_async.py +1649 -0
  745. ccxt/test/test_sync.py +1648 -0
  746. ccxt/test/tests_async.py +1558 -0
  747. ccxt/test/tests_helpers.py +287 -0
  748. ccxt/test/tests_init.py +39 -0
  749. ccxt/test/tests_sync.py +1555 -0
  750. ccxt/tetherland.py +349 -0
  751. ccxt/timex.py +1593 -0
  752. ccxt/tokocrypto.py +2405 -0
  753. ccxt/tradeogre.py +608 -0
  754. ccxt/twox.py +326 -0
  755. ccxt/ubitex.py +409 -0
  756. ccxt/upbit.py +1833 -0
  757. ccxt/vertex.py +2922 -0
  758. ccxt/wallex.py +445 -0
  759. ccxt/wavesexchange.py +2472 -0
  760. ccxt/wazirx.py +1224 -0
  761. ccxt/whitebit.py +2469 -0
  762. ccxt/woo.py +3114 -0
  763. ccxt/woofipro.py +2533 -0
  764. ccxt/xt.py +4453 -0
  765. ccxt/yobit.py +1283 -0
  766. ccxt/zaif.py +725 -0
  767. ccxt/zonda.py +1828 -0
  768. ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
  769. ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
  770. ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
  771. ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
  772. ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
ccxt/okcoin.py ADDED
@@ -0,0 +1,2936 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.base.exchange import Exchange
7
+ from ccxt.abstract.okcoin import ImplicitAPI
8
+ import hashlib
9
+ from ccxt.base.types import Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
10
+ from typing import List
11
+ from ccxt.base.errors import ExchangeError
12
+ from ccxt.base.errors import AuthenticationError
13
+ from ccxt.base.errors import PermissionDenied
14
+ from ccxt.base.errors import AccountNotEnabled
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 InvalidAddress
21
+ from ccxt.base.errors import InvalidOrder
22
+ from ccxt.base.errors import OrderNotFound
23
+ from ccxt.base.errors import CancelPending
24
+ from ccxt.base.errors import NotSupported
25
+ from ccxt.base.errors import NetworkError
26
+ from ccxt.base.errors import RateLimitExceeded
27
+ from ccxt.base.errors import ExchangeNotAvailable
28
+ from ccxt.base.errors import OnMaintenance
29
+ from ccxt.base.errors import InvalidNonce
30
+ from ccxt.base.errors import RequestTimeout
31
+ from ccxt.base.decimal_to_precision import TICK_SIZE
32
+ from ccxt.base.precise import Precise
33
+
34
+
35
+ class okcoin(Exchange, ImplicitAPI):
36
+
37
+ def describe(self):
38
+ return self.deep_extend(super(okcoin, self).describe(), {
39
+ 'id': 'okcoin',
40
+ 'name': 'OKCoin',
41
+ 'countries': ['CN', 'US'],
42
+ 'version': 'v5',
43
+ # cheapest endpoint is 100 requests per 2 seconds
44
+ # 50 requests per second => 1000 / 50 = 20ms
45
+ 'rateLimit': 20,
46
+ 'pro': True,
47
+ 'has': {
48
+ 'CORS': None,
49
+ 'spot': True,
50
+ 'margin': False,
51
+ 'swap': False,
52
+ 'future': True,
53
+ 'option': None,
54
+ 'cancelOrder': True,
55
+ 'createMarketBuyOrderWithCost': True,
56
+ 'createMarketOrderWithCost': False,
57
+ 'createMarketSellOrderWithCost': False,
58
+ 'createOrder': True,
59
+ 'fetchBalance': True,
60
+ 'fetchBorrowInterest': False,
61
+ 'fetchBorrowRate': False,
62
+ 'fetchBorrowRateHistories': False,
63
+ 'fetchBorrowRateHistory': False,
64
+ 'fetchBorrowRates': False,
65
+ 'fetchBorrowRatesPerSymbol': False,
66
+ 'fetchClosedOrders': True,
67
+ 'fetchCurrencies': True, # see below
68
+ 'fetchDepositAddress': True,
69
+ 'fetchDeposits': True,
70
+ 'fetchFundingHistory': False,
71
+ 'fetchFundingRate': False,
72
+ 'fetchFundingRateHistory': False,
73
+ 'fetchLedger': True,
74
+ 'fetchMarkets': True,
75
+ 'fetchMyTrades': True,
76
+ 'fetchOHLCV': True,
77
+ 'fetchOpenOrders': True,
78
+ 'fetchOrder': True,
79
+ 'fetchOrderBook': True,
80
+ 'fetchOrders': None,
81
+ 'fetchOrderTrades': True,
82
+ 'fetchPosition': False,
83
+ 'fetchPositions': False,
84
+ 'fetchTicker': True,
85
+ 'fetchTickers': True,
86
+ 'fetchTime': True,
87
+ 'fetchTrades': True,
88
+ 'fetchTransactions': None,
89
+ 'fetchWithdrawals': True,
90
+ 'reduceMargin': False,
91
+ 'repayCrossMargin': False,
92
+ 'repayIsolatedMargin': False,
93
+ 'setMargin': False,
94
+ 'transfer': True,
95
+ 'withdraw': True,
96
+ },
97
+ 'timeframes': {
98
+ '1m': '1m',
99
+ '3m': '3m',
100
+ '5m': '5m',
101
+ '15m': '15m',
102
+ '30m': '30m',
103
+ '1h': '1H',
104
+ '2h': '2H',
105
+ '4h': '4H',
106
+ '6h': '6H',
107
+ '12h': '12H',
108
+ '1d': '1D',
109
+ '1w': '1W',
110
+ '1M': '1M',
111
+ '3M': '3M',
112
+ },
113
+ 'hostname': 'okcoin.com',
114
+ 'urls': {
115
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295551-102fbf00-c50e-11ea-90a9-462eebba5829.jpg',
116
+ 'api': {
117
+ 'rest': 'https://www.{hostname}',
118
+ },
119
+ 'www': 'https://www.okcoin.com',
120
+ 'doc': 'https://www.okcoin.com/docs/en/',
121
+ 'fees': 'https://www.okcoin.com/coin-fees',
122
+ 'referral': 'https://www.okcoin.com/account/register?flag=activity&channelId=600001513',
123
+ 'test': {
124
+ 'rest': 'https://testnet.okex.com',
125
+ },
126
+ },
127
+ 'api': {
128
+ 'public': {
129
+ 'get': {
130
+ 'market/tickers': 1,
131
+ 'market/ticker': 1,
132
+ 'market/books': 1 / 2,
133
+ 'market/candles': 1 / 2,
134
+ 'market/history-candles': 1 / 2,
135
+ 'market/trades': 1 / 5,
136
+ 'market/history-trades': 2,
137
+ 'market/platform-24-volume': 10,
138
+ 'market/open-oracle': 50,
139
+ 'market/exchange-rate': 20,
140
+ 'public/instruments': 1,
141
+ 'public/time': 2,
142
+ },
143
+ },
144
+ 'private': {
145
+ 'get': {
146
+ # trade
147
+ 'trade/order': 1 / 3,
148
+ 'trade/orders-pending': 1 / 3,
149
+ 'trade/orders-history': 1 / 2,
150
+ 'trade/orders-history-archive': 1 / 2,
151
+ 'trade/fills': 1 / 3,
152
+ 'trade/fills-history': 2.2,
153
+ 'trade/fills-archive': 2,
154
+ 'trade/order-algo': 1,
155
+ 'trade/orders-algo-pending': 1,
156
+ 'trade/orders-algo-history': 1,
157
+ # rfq
158
+ 'otc/rfq/trade': 4,
159
+ 'otc/rfq/history': 4,
160
+ # account
161
+ 'account/balance': 2,
162
+ 'account/bills': 5 / 3,
163
+ 'account/bills-archive': 5 / 3,
164
+ 'account/config': 4,
165
+ 'account/max-size': 4,
166
+ 'account/max-avail-size': 4,
167
+ 'account/trade-fee': 4,
168
+ 'account/max-withdrawal': 4,
169
+ # funding or assets
170
+ 'asset/currencies': 5 / 3,
171
+ 'asset/balances': 5 / 3,
172
+ 'asset/asset-valuation': 10,
173
+ 'asset/transfer-state': 10,
174
+ 'asset/bills': 5 / 3,
175
+ 'asset/deposit-lightning': 5,
176
+ 'asset/deposit-address': 5 / 3,
177
+ 'asset/deposit-history': 5 / 3,
178
+ 'asset/withdrawal-history': 5 / 3,
179
+ 'asset/deposit-withdraw-status': 20,
180
+ # fiat
181
+ 'fiat/deposit-history': 5 / 3,
182
+ 'fiat-withdraw-history': 5 / 3,
183
+ 'fiat-channel': 5 / 3,
184
+ # sub-account
185
+ 'users/subaccount/list': 10,
186
+ 'users/subaccount/apiKey': 10,
187
+ 'account/subaccount/balances': 10,
188
+ 'asset/subaccount/balances': 10,
189
+ 'asset/subaccount/bills': 10,
190
+ },
191
+ 'post': {
192
+ # trade
193
+ 'trade/order': 1 / 3,
194
+ 'trade/batch-orders': 1 / 15,
195
+ 'trade/cancel-order': 1 / 3,
196
+ 'trade/cancel-batch-orders': 1 / 15,
197
+ 'trade/amend-order': 1 / 3,
198
+ 'trade/amend-batch-orders': 1 / 150,
199
+ 'trade/order-algo': 1,
200
+ 'trade/cancel-algos': 1,
201
+ 'trade/cancel-advance-algos': 1,
202
+ # rfq
203
+ 'otc/rfq/quote': 4,
204
+ 'otc/rfq/trade': 4,
205
+ # funding
206
+ 'asset/transfer': 4,
207
+ 'asset/withdrawal': 4,
208
+ 'asset/withdrawal-lightning': 4,
209
+ 'asset/withdrawal-cancel': 4,
210
+ # fiat
211
+ 'fiat/deposit': 5 / 3,
212
+ 'fiat/cancel-deposit': 5 / 3,
213
+ 'fiat/withdrawal': 5 / 3,
214
+ 'fiat/cancel-withdrawal': 5 / 3,
215
+ # sub-account
216
+ 'asset/subaccount/transfer': 10,
217
+ },
218
+ },
219
+ },
220
+ 'fees': {
221
+ 'trading': {
222
+ 'taker': 0.002,
223
+ 'maker': 0.001,
224
+ },
225
+ 'spot': {
226
+ 'taker': 0.0015,
227
+ 'maker': 0.0010,
228
+ },
229
+ },
230
+ 'requiredCredentials': {
231
+ 'apiKey': True,
232
+ 'secret': True,
233
+ 'password': True,
234
+ },
235
+ 'exceptions': {
236
+ 'exact': {
237
+ # Public error codes from 50000-53999
238
+ # General Class
239
+ '1': ExchangeError, # Operation failed
240
+ '2': ExchangeError, # Bulk operation partially succeeded
241
+ '50000': BadRequest, # Body can not be empty
242
+ '50001': OnMaintenance, # Matching engine upgrading. Please try again later
243
+ '50002': BadRequest, # Json data format error
244
+ '50004': RequestTimeout, # Endpoint request timeout(does not indicate success or failure of order, please check order status)
245
+ '50005': ExchangeNotAvailable, # API is offline or unavailable
246
+ '50006': BadRequest, # Invalid Content_Type, please use "application/json" format
247
+ '50007': AccountSuspended, # Account blocked
248
+ '50008': AuthenticationError, # User does not exist
249
+ '50009': AccountSuspended, # Account is suspended due to ongoing liquidation
250
+ '50010': ExchangeError, # User ID can not be empty
251
+ '50011': RateLimitExceeded, # Request too frequent
252
+ '50012': ExchangeError, # Account status invalid
253
+ '50013': ExchangeNotAvailable, # System is busy, please try again later
254
+ '50014': BadRequest, # Parameter {0} can not be empty
255
+ '50015': ExchangeError, # Either parameter {0} or {1} is required
256
+ '50016': ExchangeError, # Parameter {0} does not match parameter {1}
257
+ '50017': ExchangeError, # The position is frozen due to ADL. Operation restricted
258
+ '50018': ExchangeError, # Currency {0} is frozen due to ADL. Operation restricted
259
+ '50019': ExchangeError, # The account is frozen due to ADL. Operation restricted
260
+ '50020': ExchangeError, # The position is frozen due to liquidation. Operation restricted
261
+ '50021': ExchangeError, # Currency {0} is frozen due to liquidation. Operation restricted
262
+ '50022': ExchangeError, # The account is frozen due to liquidation. Operation restricted
263
+ '50023': ExchangeError, # Funding fee frozen. Operation restricted
264
+ '50024': BadRequest, # Parameter {0} and {1} can not exist at the same time
265
+ '50025': ExchangeError, # Parameter {0} count exceeds the limit {1}
266
+ '50026': ExchangeNotAvailable, # System error, please try again later.
267
+ '50027': PermissionDenied, # The account is restricted from trading
268
+ '50028': ExchangeError, # Unable to take the order, please reach out to support center for details
269
+ '50029': ExchangeError, # This instrument({0}) is unavailable at present due to risk management. Please contact customer service for help.
270
+ '50030': PermissionDenied, # No permission to use self API
271
+ '50032': AccountSuspended, # This asset is blocked, allow its trading and try again
272
+ '50033': AccountSuspended, # This instrument is blocked, allow its trading and try again
273
+ '50035': BadRequest, # This endpoint requires that APIKey must be bound to IP
274
+ '50036': BadRequest, # Invalid expTime
275
+ '50037': BadRequest, # Order expired
276
+ '50038': ExchangeError, # This feature is temporarily unavailable in demo trading
277
+ '50039': ExchangeError, # The before parameter is not available for implementing timestamp pagination
278
+ '50041': ExchangeError, # You are not currently on the whitelist, please contact customer service
279
+ '50044': BadRequest, # Must select one broker type
280
+ # API Class
281
+ '50100': ExchangeError, # API frozen, please contact customer service
282
+ '50101': AuthenticationError, # Broker id of APIKey does not match current environment
283
+ '50102': InvalidNonce, # Timestamp request expired
284
+ '50103': AuthenticationError, # Request header "OK_ACCESS_KEY" can not be empty
285
+ '50104': AuthenticationError, # Request header "OK_ACCESS_PASSPHRASE" can not be empty
286
+ '50105': AuthenticationError, # Request header "OK_ACCESS_PASSPHRASE" incorrect
287
+ '50106': AuthenticationError, # Request header "OK_ACCESS_SIGN" can not be empty
288
+ '50107': AuthenticationError, # Request header "OK_ACCESS_TIMESTAMP" can not be empty
289
+ '50108': ExchangeError, # Exchange ID does not exist
290
+ '50109': ExchangeError, # Exchange domain does not exist
291
+ '50110': PermissionDenied, # Invalid IP
292
+ '50111': AuthenticationError, # Invalid OK_ACCESS_KEY
293
+ '50112': AuthenticationError, # Invalid OK_ACCESS_TIMESTAMP
294
+ '50113': AuthenticationError, # Invalid signature
295
+ '50114': AuthenticationError, # Invalid authorization
296
+ '50115': BadRequest, # Invalid request method
297
+ # Trade Class
298
+ '51000': BadRequest, # Parameter {0} error
299
+ '51001': BadSymbol, # Instrument ID does not exist
300
+ '51002': BadSymbol, # Instrument ID does not match underlying index
301
+ '51003': BadRequest, # Either client order ID or order ID is required
302
+ '51004': InvalidOrder, # Order amount exceeds current tier limit
303
+ '51005': InvalidOrder, # Order amount exceeds the limit
304
+ '51006': InvalidOrder, # Order price out of the limit
305
+ '51007': InvalidOrder, # Order placement failed. Order amount should be at least 1 contract(showing up when placing an order with less than 1 contract)
306
+ '51008': InsufficientFunds, # Order placement failed due to insufficient balance
307
+ '51009': AccountSuspended, # Order placement function is blocked by the platform
308
+ '51010': AccountNotEnabled, # Account level too low {"code":"1","data":[{"clOrdId":"uJrfGFth9F","ordId":"","sCode":"51010","sMsg":"The current account mode does not support self API interface. ","tag":""}],"msg":"Operation failed."}
309
+ '51011': InvalidOrder, # Duplicated order ID
310
+ '51012': BadSymbol, # Token does not exist
311
+ '51014': BadSymbol, # Index does not exist
312
+ '51015': BadSymbol, # Instrument ID does not match instrument type
313
+ '51016': InvalidOrder, # Duplicated client order ID
314
+ '51017': ExchangeError, # Borrow amount exceeds the limit
315
+ '51018': ExchangeError, # User with option account can not hold net short positions
316
+ '51019': ExchangeError, # No net long positions can be held under isolated margin mode in options
317
+ '51020': InvalidOrder, # Order amount should be greater than the min available amount
318
+ '51023': ExchangeError, # Position does not exist
319
+ '51024': AccountSuspended, # Unified accountblocked
320
+ '51025': ExchangeError, # Order count exceeds the limit
321
+ '51026': BadSymbol, # Instrument type does not match underlying index
322
+ '51030': InvalidOrder, # Funding fee is being settled.
323
+ '51031': InvalidOrder, # This order price is not within the closing price range
324
+ '51032': InvalidOrder, # Closing all positions at market price.
325
+ '51033': InvalidOrder, # The total amount per order for self pair has reached the upper limit.
326
+ '51037': InvalidOrder, # The current account risk status only supports you to place IOC orders that can reduce the risk of your account.
327
+ '51038': InvalidOrder, # There is already an IOC order under the current risk module that reduces the risk of the account.
328
+ '51044': InvalidOrder, # The order type {0}, {1} is not allowed to set stop loss and take profit
329
+ '51046': InvalidOrder, # The take profit trigger price must be higher than the order price
330
+ '51047': InvalidOrder, # The stop loss trigger price must be lower than the order price
331
+ '51048': InvalidOrder, # The take profit trigger price should be lower than the order price
332
+ '51049': InvalidOrder, # The stop loss trigger price should be higher than the order price
333
+ '51050': InvalidOrder, # The take profit trigger price should be higher than the best ask price
334
+ '51051': InvalidOrder, # The stop loss trigger price should be lower than the best ask price
335
+ '51052': InvalidOrder, # The take profit trigger price should be lower than the best bid price
336
+ '51053': InvalidOrder, # The stop loss trigger price should be higher than the best bid price
337
+ '51054': BadRequest, # Getting information timed out, please try again later
338
+ '51056': InvalidOrder, # Action not allowed
339
+ '51058': InvalidOrder, # No available position for self algo order
340
+ '51059': InvalidOrder, # Strategy for the current state does not support self operation
341
+ '51100': InvalidOrder, # Trading amount does not meet the min tradable amount
342
+ '51102': InvalidOrder, # Entered amount exceeds the max pending count
343
+ '51103': InvalidOrder, # Entered amount exceeds the max pending order count of the underlying asset
344
+ '51108': InvalidOrder, # Positions exceed the limit for closing out with the market price
345
+ '51109': InvalidOrder, # No available offer
346
+ '51110': InvalidOrder, # You can only place a limit order after Call Auction has started
347
+ '51111': BadRequest, # Maximum {0} orders can be placed in bulk
348
+ '51112': InvalidOrder, # Close order size exceeds your available size
349
+ '51113': RateLimitExceeded, # Market-price liquidation requests too frequent
350
+ '51115': InvalidOrder, # Cancel all pending close-orders before liquidation
351
+ '51116': InvalidOrder, # Order price or trigger price exceeds {0}
352
+ '51117': InvalidOrder, # Pending close-orders count exceeds limit
353
+ '51118': InvalidOrder, # Total amount should exceed the min amount per order
354
+ '51119': InsufficientFunds, # Order placement failed due to insufficient balance
355
+ '51120': InvalidOrder, # Order quantity is less than {0}, please try again
356
+ '51121': InvalidOrder, # Order count should be the integer multiples of the lot size
357
+ '51122': InvalidOrder, # Order price should be higher than the min price {0}
358
+ '51124': InvalidOrder, # You can only place limit orders during call auction
359
+ '51125': InvalidOrder, # Currently there are reduce + reverse position pending orders in margin trading. Please cancel all reduce + reverse position pending orders and continue
360
+ '51126': InvalidOrder, # Currently there are reduce only pending orders in margin trading.Please cancel all reduce only pending orders and continue
361
+ '51127': InsufficientFunds, # Available balance is 0
362
+ '51128': InvalidOrder, # Multi-currency margin account can not do cross-margin trading
363
+ '51129': InvalidOrder, # The value of the position and buy order has reached the position limit, and no further buying is allowed
364
+ '51130': BadSymbol, # Fixed margin currency error
365
+ '51131': InsufficientFunds, # Insufficient balance
366
+ '51132': InvalidOrder, # Your position amount is negative and less than the minimum trading amount
367
+ '51133': InvalidOrder, # Reduce-only feature is unavailable for the spot transactions by multi-currency margin account
368
+ '51134': InvalidOrder, # Closing failed. Please check your holdings and pending orders
369
+ '51135': InvalidOrder, # Your closing price has triggered the limit price, and the max buy price is {0}
370
+ '51136': InvalidOrder, # Your closing price has triggered the limit price, and the min sell price is {0}
371
+ '51137': InvalidOrder, # Your opening price has triggered the limit price, and the max buy price is {0}
372
+ '51138': InvalidOrder, # Your opening price has triggered the limit price, and the min sell price is {0}
373
+ '51139': InvalidOrder, # Reduce-only feature is unavailable for the spot transactions by simple account
374
+ '51156': BadRequest, # You're leading trades in long/short mode and can't use self API endpoint to close positions
375
+ '51159': BadRequest, # You're leading trades in buy/sell mode. If you want to place orders using self API endpoint, the orders must be in the same direction existing positions and open orders.
376
+ '51162': InvalidOrder, # You have {instrument} open orders. Cancel these orders and try again
377
+ '51163': InvalidOrder, # You hold {instrument} positions. Close these positions and try again
378
+ '51166': InvalidOrder, # Currently, we don't support leading trades with self instrument
379
+ '51174': InvalidOrder, # The number of {param0} pending orders reached the upper limit of {param1}(orders).
380
+ '51201': InvalidOrder, # Value of per market order cannot exceed 100,000 USDT
381
+ '51202': InvalidOrder, # Market - order amount exceeds the max amount
382
+ '51203': InvalidOrder, # Order amount exceeds the limit {0}
383
+ '51204': InvalidOrder, # The price for the limit order can not be empty
384
+ '51205': InvalidOrder, # Reduce-Only is not available
385
+ '51250': InvalidOrder, # Algo order price is out of the available range
386
+ '51251': InvalidOrder, # Algo order type error(when user place an iceberg order)
387
+ '51252': InvalidOrder, # Algo order price is out of the available range
388
+ '51253': InvalidOrder, # Average amount exceeds the limit of per iceberg order
389
+ '51254': InvalidOrder, # Iceberg average amount error(when user place an iceberg order)
390
+ '51255': InvalidOrder, # Limit of per iceberg order: Total amount/1000 < x <= Total amount
391
+ '51256': InvalidOrder, # Iceberg order price variance error
392
+ '51257': InvalidOrder, # Trail order callback rate error
393
+ '51258': InvalidOrder, # Trail - order placement failed. The trigger price of a sell order should be higher than the last transaction price
394
+ '51259': InvalidOrder, # Trail - order placement failed. The trigger price of a buy order should be lower than the last transaction price
395
+ '51260': InvalidOrder, # Maximum {0} pending trail - orders can be held at the same time
396
+ '51261': InvalidOrder, # Each user can hold up to {0} pending stop - orders at the same time
397
+ '51262': InvalidOrder, # Maximum {0} pending iceberg orders can be held at the same time
398
+ '51263': InvalidOrder, # Maximum {0} pending time-weighted orders can be held at the same time
399
+ '51264': InvalidOrder, # Average amount exceeds the limit of per time-weighted order
400
+ '51265': InvalidOrder, # Time-weighted order limit error
401
+ '51267': InvalidOrder, # Time-weighted order strategy initiative rate error
402
+ '51268': InvalidOrder, # Time-weighted order strategy initiative range error
403
+ '51269': InvalidOrder, # Time-weighted order interval error, the interval should be {0}<= x<={1}
404
+ '51270': InvalidOrder, # The limit of time-weighted order price variance is 0 < x <= 1%
405
+ '51271': InvalidOrder, # Sweep ratio should be 0 < x <= 100%
406
+ '51272': InvalidOrder, # Price variance should be 0 < x <= 1%
407
+ '51273': InvalidOrder, # Total amount should be more than {0}
408
+ '51274': InvalidOrder, # Total quantity of time-weighted order must be larger than single order limit
409
+ '51275': InvalidOrder, # The amount of single stop-market order can not exceed the upper limit
410
+ '51276': InvalidOrder, # Stop - Market orders cannot specify a price
411
+ '51277': InvalidOrder, # TP trigger price can not be higher than the last price
412
+ '51278': InvalidOrder, # SL trigger price can not be lower than the last price
413
+ '51279': InvalidOrder, # TP trigger price can not be lower than the last price
414
+ '51280': InvalidOrder, # SL trigger price can not be higher than the last price
415
+ '51321': InvalidOrder, # You're leading trades. Currently, we don't support leading trades with arbitrage, iceberg, or TWAP bots
416
+ '51322': InvalidOrder, # You're leading trades that have been filled at market price. We've canceled your open stop orders to close your positions
417
+ '51323': BadRequest, # You're already leading trades with take profit or stop loss settings. Cancel your existing stop orders to proceed
418
+ '51324': BadRequest, # As a lead trader, you hold positions in {instrument}. To close your positions, place orders in the amount that equals the available amount for closing
419
+ '51325': InvalidOrder, # As a lead trader, you must use market price when placing stop orders
420
+ '51327': InvalidOrder, # closeFraction is only available for futures and perpetual swaps
421
+ '51328': InvalidOrder, # closeFraction is only available for reduceOnly orders
422
+ '51329': InvalidOrder, # closeFraction is only available in NET mode
423
+ '51330': InvalidOrder, # closeFraction is only available for stop market orders
424
+ '51400': OrderNotFound, # Cancellation failed order does not exist
425
+ '51401': OrderNotFound, # Cancellation failed order is already canceled
426
+ '51402': OrderNotFound, # Cancellation failed order is already completed
427
+ '51403': InvalidOrder, # Cancellation failed order type does not support cancellation
428
+ '51404': InvalidOrder, # Order cancellation unavailable during the second phase of call auction
429
+ '51405': ExchangeError, # Cancellation failed do not have any pending orders
430
+ '51406': ExchangeError, # Canceled - order count exceeds the limit {0}
431
+ '51407': BadRequest, # Either order ID or client order ID is required
432
+ '51408': ExchangeError, # Pair ID or name does not match the order info
433
+ '51409': ExchangeError, # Either pair ID or pair name ID is required
434
+ '51410': CancelPending, # Cancellation failed order is already under cancelling status
435
+ '51500': ExchangeError, # Either order price or amount is required
436
+ '51501': ExchangeError, # Maximum {0} orders can be modified
437
+ '51502': InsufficientFunds, # Order modification failed for insufficient margin
438
+ '51503': ExchangeError, # Order modification failed order does not exist
439
+ '51506': ExchangeError, # Order modification unavailable for the order type
440
+ '51508': ExchangeError, # Orders are not allowed to be modified during the call auction
441
+ '51509': ExchangeError, # Modification failed order has been canceled
442
+ '51510': ExchangeError, # Modification failed order has been completed
443
+ '51511': ExchangeError, # Modification failed order price did not meet the requirement for Post Only
444
+ '51600': ExchangeError, # Status not found
445
+ '51601': ExchangeError, # Order status and order ID cannot exist at the same time
446
+ '51602': ExchangeError, # Either order status or order ID is required
447
+ '51603': OrderNotFound, # Order does not exist
448
+ '51732': AuthenticationError, # Required user KYC level not met
449
+ '51733': AuthenticationError, # User is under risk control
450
+ '51734': AuthenticationError, # User KYC Country is not supported
451
+ '51735': ExchangeError, # Sub-account is not supported
452
+ '51736': InsufficientFunds, # Insufficient {ccy} balance
453
+ # Data class
454
+ '52000': ExchangeError, # No updates
455
+ # SPOT/MARGIN error codes 54000-54999
456
+ '54000': ExchangeError, # Margin transactions unavailable
457
+ '54001': ExchangeError, # Only Multi-currency margin account can be set to borrow coins automatically
458
+ # FUNDING error codes 58000-58999
459
+ '58000': ExchangeError, # Account type {0} does not supported when getting the sub-account balance
460
+ '58001': AuthenticationError, # Incorrect trade password
461
+ '58002': PermissionDenied, # Please activate Savings Account first
462
+ '58003': ExchangeError, # Currency type is not supported by Savings Account
463
+ '58004': AccountSuspended, # Account blocked(transfer & withdrawal endpoint: either end of the account does not authorize the transfer)
464
+ '58005': ExchangeError, # The redeemed amount must be no greater than {0}
465
+ '58006': ExchangeError, # Service unavailable for token {0}
466
+ '58007': ExchangeError, # Abnormal Assets interface. Please try again later
467
+ '58100': ExchangeError, # The trading product triggers risk control, and the platform has suspended the fund transfer-out function with related users. Please wait patiently
468
+ '58101': AccountSuspended, # Transfer suspended(transfer endpoint: either end of the account does not authorize the transfer)
469
+ '58102': RateLimitExceeded, # Too frequent transfer(transfer too frequently)
470
+ '58103': ExchangeError, # Parent account user id does not match sub-account user id
471
+ '58104': ExchangeError, # Since your P2P transaction is abnormal, you are restricted from making fund transfers. Please contact customer support to remove the restriction
472
+ '58105': ExchangeError, # Since your P2P transaction is abnormal, you are restricted from making fund transfers. Please transfer funds on our website or app to complete identity verification
473
+ '58106': ExchangeError, # Please enable the account for spot contract
474
+ '58107': ExchangeError, # Please enable the account for futures contract
475
+ '58108': ExchangeError, # Please enable the account for option contract
476
+ '58109': ExchangeError, # Please enable the account for swap contract
477
+ '58110': ExchangeError, # The contract triggers risk control, and the platform has suspended the fund transfer function of it. Please wait patiently
478
+ '58111': ExchangeError, # Funds transfer unavailable perpetual contract is charging the funding fee. Please try again later
479
+ '58112': ExchangeError, # Your fund transfer failed. Please try again later
480
+ '58114': ExchangeError, # Transfer amount must be more than 0
481
+ '58115': ExchangeError, # Sub-account does not exist
482
+ '58116': ExchangeError, # Transfer amount exceeds the limit
483
+ '58117': ExchangeError, # Account assets are abnormal, please deal with negative assets before transferring
484
+ '58125': BadRequest, # Non-tradable assets can only be transferred from sub-accounts to main accounts
485
+ '58126': BadRequest, # Non-tradable assets can only be transferred between funding accounts
486
+ '58127': BadRequest, # Main account API Key does not support current transfer 'type' parameter. Please refer to the API documentation.
487
+ '58128': BadRequest, # Sub-account API Key does not support current transfer 'type' parameter. Please refer to the API documentation.
488
+ '58200': ExchangeError, # Withdrawal from {0} to {1} is unavailable for self currency
489
+ '58201': ExchangeError, # Withdrawal amount exceeds the daily limit
490
+ '58202': ExchangeError, # The minimum withdrawal amount for NEO is 1, and the amount must be an integer
491
+ '58203': InvalidAddress, # Please add a withdrawal address
492
+ '58204': AccountSuspended, # Withdrawal suspended
493
+ '58205': ExchangeError, # Withdrawal amount exceeds the upper limit
494
+ '58206': ExchangeError, # Withdrawal amount is lower than the lower limit
495
+ '58207': InvalidAddress, # Withdrawal failed due to address error
496
+ '58208': ExchangeError, # Withdrawal failed. Please link your email
497
+ '58209': ExchangeError, # Withdrawal failed. Withdraw feature is not available for sub-accounts
498
+ '58210': ExchangeError, # Withdrawal fee exceeds the upper limit
499
+ '58211': ExchangeError, # Withdrawal fee is lower than the lower limit(withdrawal endpoint: incorrect fee)
500
+ '58212': ExchangeError, # Withdrawal fee should be {0}% of the withdrawal amount
501
+ '58213': AuthenticationError, # Please set trading password before withdrawal
502
+ '58221': BadRequest, # Missing label of withdrawal address.
503
+ '58222': BadRequest, # Illegal withdrawal address.
504
+ '58224': BadRequest, # This type of crypto does not support on-chain withdrawing to OKX addresses. Please withdraw through internal transfers.
505
+ '58227': BadRequest, # Withdrawal of non-tradable assets can be withdrawn all at once only
506
+ '58228': BadRequest, # Withdrawal of non-tradable assets requires that the API Key must be bound to an IP
507
+ '58229': InsufficientFunds, # Insufficient funding account balance to pay fees {fee} USDT
508
+ '58300': ExchangeError, # Deposit-address count exceeds the limit
509
+ '58350': InsufficientFunds, # Insufficient balance
510
+ # Account error codes 59000-59999
511
+ '59000': ExchangeError, # Your settings failed have positions or open orders
512
+ '59001': ExchangeError, # Switching unavailable have borrowings
513
+ '59100': ExchangeError, # You have open positions. Please cancel all open positions before changing the leverage
514
+ '59101': ExchangeError, # You have pending orders with isolated positions. Please cancel all the pending orders and adjust the leverage
515
+ '59102': ExchangeError, # Leverage exceeds the maximum leverage. Please adjust the leverage
516
+ '59103': InsufficientFunds, # Leverage is too low and no sufficient margin in your account. Please adjust the leverage
517
+ '59104': ExchangeError, # The leverage is too high. The borrowed position has exceeded the maximum position of self leverage. Please adjust the leverage
518
+ '59105': ExchangeError, # Leverage can not be less than {0}. Please adjust the leverage
519
+ '59106': ExchangeError, # The max available margin corresponding to your order tier is {0}. Please adjust your margin and place a new order
520
+ '59107': ExchangeError, # You have pending orders under the service, please modify the leverage after canceling all pending orders
521
+ '59108': InsufficientFunds, # Low leverage and insufficient margin, please adjust the leverage
522
+ '59109': ExchangeError, # Account equity less than the required margin amount after adjustment. Please adjust the leverage
523
+ '59128': InvalidOrder, # As a lead trader, you can't lead trades in {instrument} with leverage higher than {num}
524
+ '59200': InsufficientFunds, # Insufficient account balance
525
+ '59201': InsufficientFunds, # Negative account balance
526
+ '59216': BadRequest, # The position doesn't exist. Please try again
527
+ '59300': ExchangeError, # Margin call failed. Position does not exist
528
+ '59301': ExchangeError, # Margin adjustment failed for exceeding the max limit
529
+ '59313': ExchangeError, # Unable to repay. You haven't borrowed any {ccy} {ccyPair} in Quick margin mode.
530
+ '59401': ExchangeError, # Holdings already reached the limit
531
+ '59500': ExchangeError, # Only the APIKey of the main account has permission
532
+ '59501': ExchangeError, # Only 50 APIKeys can be created per account
533
+ '59502': ExchangeError, # Note name cannot be duplicate with the currently created APIKey note name
534
+ '59503': ExchangeError, # Each APIKey can bind up to 20 IP addresses
535
+ '59504': ExchangeError, # The sub account does not support the withdrawal function
536
+ '59505': ExchangeError, # The passphrase format is incorrect
537
+ '59506': ExchangeError, # APIKey does not exist
538
+ '59507': ExchangeError, # The two accounts involved in a transfer must be two different sub accounts under the same parent account
539
+ '59508': AccountSuspended, # The sub account of {0} is suspended
540
+ # WebSocket error Codes from 60000-63999
541
+ '60001': AuthenticationError, # "OK_ACCESS_KEY" can not be empty
542
+ '60002': AuthenticationError, # "OK_ACCESS_SIGN" can not be empty
543
+ '60003': AuthenticationError, # "OK_ACCESS_PASSPHRASE" can not be empty
544
+ '60004': AuthenticationError, # Invalid OK_ACCESS_TIMESTAMP
545
+ '60005': AuthenticationError, # Invalid OK_ACCESS_KEY
546
+ '60006': InvalidNonce, # Timestamp request expired
547
+ '60007': AuthenticationError, # Invalid sign
548
+ '60008': AuthenticationError, # Login is not supported for public channels
549
+ '60009': AuthenticationError, # Login failed
550
+ '60010': AuthenticationError, # Already logged in
551
+ '60011': AuthenticationError, # Please log in
552
+ '60012': BadRequest, # Illegal request
553
+ '60013': BadRequest, # Invalid args
554
+ '60014': RateLimitExceeded, # Requests too frequent
555
+ '60015': NetworkError, # Connection closed was no data transmission in the last 30 seconds
556
+ '60016': ExchangeNotAvailable, # Buffer is full, cannot write data
557
+ '60017': BadRequest, # Invalid url path
558
+ '60018': BadRequest, # The {0} {1} {2} {3} {4} does not exist
559
+ '60019': BadRequest, # Invalid op {op}
560
+ '63999': ExchangeError, # Internal system error
561
+ '70010': BadRequest, # Timestamp parameters need to be in Unix timestamp format in milliseconds.
562
+ '70013': BadRequest, # endTs needs to be bigger than or equal to beginTs.
563
+ '70016': BadRequest, # Please specify your instrument settings for at least one instType.
564
+ },
565
+ 'broad': {
566
+ 'Internal Server Error': ExchangeNotAvailable, # {"code":500,"data":{},"detailMsg":"","error_code":"500","error_message":"Internal Server Error","msg":"Internal Server Error"}
567
+ 'server error': ExchangeNotAvailable, # {"code":500,"data":{},"detailMsg":"","error_code":"500","error_message":"server error 1236805249","msg":"server error 1236805249"}
568
+ },
569
+ },
570
+ 'precisionMode': TICK_SIZE,
571
+ 'options': {
572
+ 'fetchOHLCV': {
573
+ 'type': 'Candles', # Candles or HistoryCandles
574
+ },
575
+ 'createMarketBuyOrderRequiresPrice': True,
576
+ 'fetchMarkets': ['spot'],
577
+ 'defaultType': 'spot', # 'account', 'spot', 'futures', 'swap', 'option'
578
+ 'accountsByType': {
579
+ 'classic': '1',
580
+ 'spot': '1',
581
+ 'funding': '6',
582
+ 'main': '6',
583
+ 'unified': '18',
584
+ },
585
+ 'accountsById': {
586
+ '1': 'spot',
587
+ '6': 'funding',
588
+ '18': 'unified',
589
+ },
590
+ 'auth': {
591
+ 'time': 'public',
592
+ 'currencies': 'private',
593
+ 'instruments': 'public',
594
+ 'rate': 'public',
595
+ '{instrument_id}/constituents': 'public',
596
+ },
597
+ 'warnOnFetchCurrenciesWithoutAuthorization': False,
598
+ 'defaultNetwork': 'ERC20',
599
+ 'networks': {
600
+ 'ERC20': 'Ethereum',
601
+ },
602
+ },
603
+ 'commonCurrencies': {
604
+ # OKEX refers to ERC20 version of Aeternity(AEToken)
605
+ 'AE': 'AET', # https://github.com/ccxt/ccxt/issues/4981
606
+ 'BOX': 'DefiBox',
607
+ 'HOT': 'Hydro Protocol',
608
+ 'HSR': 'HC',
609
+ 'MAG': 'Maggie',
610
+ 'SBTC': 'Super Bitcoin',
611
+ 'TRADE': 'Unitrade',
612
+ 'YOYO': 'YOYOW',
613
+ 'WIN': 'WinToken', # https://github.com/ccxt/ccxt/issues/5701
614
+ },
615
+ })
616
+
617
+ def fetch_time(self, params={}):
618
+ """
619
+ fetches the current integer timestamp in milliseconds from the exchange server
620
+ :param dict [params]: extra parameters specific to the exchange API endpoint
621
+ :returns int: the current integer timestamp in milliseconds from the exchange server
622
+ """
623
+ response = self.publicGetPublicTime(params)
624
+ #
625
+ # {
626
+ # "iso": "2015-01-07T23:47:25.201Z",
627
+ # "epoch": 1420674445.201
628
+ # }
629
+ #
630
+ return self.parse8601(self.safe_string(response, 'iso'))
631
+
632
+ def fetch_markets(self, params={}) -> List[Market]:
633
+ """
634
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-public-data-get-instruments
635
+ retrieves data on all markets for okcoin
636
+ :param dict [params]: extra parameters specific to the exchange API endpoint
637
+ :returns dict[]: an array of objects representing market data
638
+ """
639
+ request: dict = {
640
+ 'instType': 'SPOT',
641
+ }
642
+ response = self.publicGetPublicInstruments(self.extend(request, params))
643
+ markets = self.safe_value(response, 'data', [])
644
+ return self.parse_markets(markets)
645
+
646
+ def parse_market(self, market: dict) -> Market:
647
+ #
648
+ # spot markets
649
+ #
650
+ # {
651
+ # "base_currency": "EOS",
652
+ # "instrument_id": "EOS-OKB",
653
+ # "min_size": "0.01",
654
+ # "quote_currency": "OKB",
655
+ # "size_increment": "0.000001",
656
+ # "tick_size": "0.0001"
657
+ # }
658
+ #
659
+ id = self.safe_string(market, 'instId')
660
+ type = self.safe_string_lower(market, 'instType')
661
+ if type == 'futures':
662
+ type = 'future'
663
+ spot = (type == 'spot')
664
+ future = (type == 'future')
665
+ swap = (type == 'swap')
666
+ option = (type == 'option')
667
+ contract = swap or future or option
668
+ baseId = self.safe_string(market, 'baseCcy')
669
+ quoteId = self.safe_string(market, 'quoteCcy')
670
+ base = self.safe_currency_code(baseId)
671
+ quote = self.safe_currency_code(quoteId)
672
+ symbol = base + '/' + quote
673
+ tickSize = self.safe_string(market, 'tickSz')
674
+ fees = self.safe_value_2(self.fees, type, 'trading', {})
675
+ maxLeverage = self.safe_string(market, 'lever', '1')
676
+ maxLeverage = Precise.string_max(maxLeverage, '1')
677
+ maxSpotCost = self.safe_number(market, 'maxMktSz')
678
+ return self.extend(fees, {
679
+ 'id': id,
680
+ 'symbol': symbol,
681
+ 'base': base,
682
+ 'quote': quote,
683
+ 'settle': None,
684
+ 'baseId': baseId,
685
+ 'quoteId': quoteId,
686
+ 'settleId': None,
687
+ 'type': type,
688
+ 'spot': spot,
689
+ 'margin': spot and (Precise.string_gt(maxLeverage, '1')),
690
+ 'swap': False,
691
+ 'future': False,
692
+ 'option': False,
693
+ 'active': True,
694
+ 'contract': False,
695
+ 'linear': None,
696
+ 'inverse': None,
697
+ 'contractSize': self.safe_number(market, 'ctVal') if contract else None,
698
+ 'expiry': None,
699
+ 'expiryDatetime': None,
700
+ 'strike': None,
701
+ 'optionType': None,
702
+ 'created': self.safe_integer(market, 'listTime'),
703
+ 'precision': {
704
+ 'amount': self.safe_number(market, 'lotSz'),
705
+ 'price': self.parse_number(tickSize),
706
+ },
707
+ 'limits': {
708
+ 'leverage': {
709
+ 'min': self.parse_number('1'),
710
+ 'max': self.parse_number(maxLeverage),
711
+ },
712
+ 'amount': {
713
+ 'min': self.safe_number(market, 'minSz'),
714
+ 'max': None,
715
+ },
716
+ 'price': {
717
+ 'min': None,
718
+ 'max': None,
719
+ },
720
+ 'cost': {
721
+ 'min': None,
722
+ 'max': None if contract else maxSpotCost,
723
+ },
724
+ },
725
+ 'info': market,
726
+ })
727
+
728
+ def safe_network(self, networkId):
729
+ networksById: dict = {
730
+ 'Bitcoin': 'BTC',
731
+ 'Omni': 'OMNI',
732
+ 'TRON': 'TRC20',
733
+ }
734
+ return self.safe_string(networksById, networkId, networkId)
735
+
736
+ def fetch_currencies(self, params={}) -> Currencies:
737
+ """
738
+ fetches all available currencies on an exchange
739
+ :param dict [params]: extra parameters specific to the exchange API endpoint
740
+ :returns dict: an associative dictionary of currencies
741
+ """
742
+ if not self.check_required_credentials(False):
743
+ if self.options['warnOnFetchCurrenciesWithoutAuthorization']:
744
+ raise ExchangeError(self.id + ' fetchCurrencies() is a private API endpoint that requires authentication with API keys. Set the API keys on the exchange instance or exchange.options["warnOnFetchCurrenciesWithoutAuthorization"] = False to suppress self warning message.')
745
+ return None
746
+ else:
747
+ response = self.privateGetAssetCurrencies(params)
748
+ data = self.safe_value(response, 'data', [])
749
+ result: dict = {}
750
+ dataByCurrencyId = self.group_by(data, 'ccy')
751
+ currencyIds = list(dataByCurrencyId.keys())
752
+ for i in range(0, len(currencyIds)):
753
+ currencyId = currencyIds[i]
754
+ currency = self.safe_currency(currencyId)
755
+ code = currency['code']
756
+ chains = dataByCurrencyId[currencyId]
757
+ networks: dict = {}
758
+ currencyActive = False
759
+ depositEnabled = False
760
+ withdrawEnabled = False
761
+ maxPrecision = None
762
+ for j in range(0, len(chains)):
763
+ chain = chains[j]
764
+ canDeposit = self.safe_value(chain, 'canDep')
765
+ depositEnabled = canDeposit if (canDeposit) else depositEnabled
766
+ canWithdraw = self.safe_value(chain, 'canWd')
767
+ withdrawEnabled = canWithdraw if (canWithdraw) else withdrawEnabled
768
+ canInternal = self.safe_value(chain, 'canInternal')
769
+ active = True if (canDeposit and canWithdraw and canInternal) else False
770
+ currencyActive = active if (active) else currencyActive
771
+ networkId = self.safe_string(chain, 'chain')
772
+ if (networkId is not None) and (networkId.find('-') >= 0):
773
+ parts = networkId.split('-')
774
+ chainPart = self.safe_string(parts, 1, networkId)
775
+ networkCode = self.safe_network(chainPart)
776
+ precision = self.parse_precision(self.safe_string(chain, 'wdTickSz'))
777
+ if maxPrecision is None:
778
+ maxPrecision = precision
779
+ else:
780
+ maxPrecision = Precise.string_min(maxPrecision, precision)
781
+ networks[networkCode] = {
782
+ 'id': networkId,
783
+ 'network': networkCode,
784
+ 'active': active,
785
+ 'deposit': canDeposit,
786
+ 'withdraw': canWithdraw,
787
+ 'fee': self.safe_number(chain, 'minFee'),
788
+ 'precision': self.parse_number(precision),
789
+ 'limits': {
790
+ 'withdraw': {
791
+ 'min': self.safe_number(chain, 'minWd'),
792
+ 'max': self.safe_number(chain, 'maxWd'),
793
+ },
794
+ },
795
+ 'info': chain,
796
+ }
797
+ firstChain = self.safe_value(chains, 0)
798
+ result[code] = {
799
+ 'info': chains,
800
+ 'code': code,
801
+ 'id': currencyId,
802
+ 'name': self.safe_string(firstChain, 'name'),
803
+ 'active': currencyActive,
804
+ 'deposit': depositEnabled,
805
+ 'withdraw': withdrawEnabled,
806
+ 'fee': None,
807
+ 'precision': self.parse_number(maxPrecision),
808
+ 'limits': {
809
+ 'amount': {
810
+ 'min': None,
811
+ 'max': None,
812
+ },
813
+ },
814
+ 'networks': networks,
815
+ }
816
+ return result
817
+
818
+ def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
819
+ """
820
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-order-book
821
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
822
+ :param str symbol: unified symbol of the market to fetch the order book for
823
+ :param int [limit]: the maximum amount of order book entries to return
824
+ :param dict [params]: extra parameters specific to the exchange API endpoint
825
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
826
+ """
827
+ self.load_markets()
828
+ market = self.market(symbol)
829
+ request: dict = {
830
+ 'instId': market['id'],
831
+ }
832
+ limit = 20 if (limit is None) else limit
833
+ if limit is not None:
834
+ request['sz'] = limit # max 400
835
+ response = self.publicGetMarketBooks(self.extend(request, params))
836
+ #
837
+ # {
838
+ # "code": "0",
839
+ # "msg": "",
840
+ # "data": [
841
+ # {
842
+ # "asks": [
843
+ # ["0.07228","4.211619","0","2"], # price, amount, liquidated orders, total open orders
844
+ # ["0.0723","299.880364","0","2"],
845
+ # ["0.07231","3.72832","0","1"],
846
+ # ],
847
+ # "bids": [
848
+ # ["0.07221","18.5","0","1"],
849
+ # ["0.0722","18.5","0","1"],
850
+ # ["0.07219","0.505407","0","1"],
851
+ # ],
852
+ # "ts": "1621438475342"
853
+ # }
854
+ # ]
855
+ # }
856
+ #
857
+ data = self.safe_value(response, 'data', [])
858
+ first = self.safe_value(data, 0, {})
859
+ timestamp = self.safe_integer(first, 'ts')
860
+ return self.parse_order_book(first, symbol, timestamp)
861
+
862
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
863
+ #
864
+ # {
865
+ # "instType": "SPOT",
866
+ # "instId": "ETH-BTC",
867
+ # "last": "0.07319",
868
+ # "lastSz": "0.044378",
869
+ # "askPx": "0.07322",
870
+ # "askSz": "4.2",
871
+ # "bidPx": "0.0732",
872
+ # "bidSz": "6.050058",
873
+ # "open24h": "0.07801",
874
+ # "high24h": "0.07975",
875
+ # "low24h": "0.06019",
876
+ # "volCcy24h": "11788.887619",
877
+ # "vol24h": "167493.829229",
878
+ # "ts": "1621440583784",
879
+ # "sodUtc0": "0.07872",
880
+ # "sodUtc8": "0.07345"
881
+ # }
882
+ #
883
+ timestamp = self.safe_integer(ticker, 'ts')
884
+ marketId = self.safe_string(ticker, 'instId')
885
+ market = self.safe_market(marketId, market, '-')
886
+ symbol = market['symbol']
887
+ last = self.safe_string(ticker, 'last')
888
+ open = self.safe_string(ticker, 'open24h')
889
+ spot = self.safe_bool(market, 'spot', False)
890
+ quoteVolume = self.safe_string(ticker, 'volCcy24h') if spot else None
891
+ baseVolume = self.safe_string(ticker, 'vol24h')
892
+ high = self.safe_string(ticker, 'high24h')
893
+ low = self.safe_string(ticker, 'low24h')
894
+ return self.safe_ticker({
895
+ 'symbol': symbol,
896
+ 'timestamp': timestamp,
897
+ 'datetime': self.iso8601(timestamp),
898
+ 'high': high,
899
+ 'low': low,
900
+ 'bid': self.safe_string(ticker, 'bidPx'),
901
+ 'bidVolume': self.safe_string(ticker, 'bidSz'),
902
+ 'ask': self.safe_string(ticker, 'askPx'),
903
+ 'askVolume': self.safe_string(ticker, 'askSz'),
904
+ 'vwap': None,
905
+ 'open': open,
906
+ 'close': last,
907
+ 'last': last,
908
+ 'previousClose': None,
909
+ 'change': None,
910
+ 'percentage': None,
911
+ 'average': None,
912
+ 'baseVolume': baseVolume,
913
+ 'quoteVolume': quoteVolume,
914
+ 'info': ticker,
915
+ }, market)
916
+
917
+ def fetch_ticker(self, symbol: str, params={}) -> Ticker:
918
+ """
919
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-ticker
920
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
921
+ :param str symbol: unified symbol of the market to fetch the ticker for
922
+ :param dict [params]: extra parameters specific to the exchange API endpoint
923
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
924
+ """
925
+ self.load_markets()
926
+ market = self.market(symbol)
927
+ request: dict = {
928
+ 'instId': market['id'],
929
+ }
930
+ response = self.publicGetMarketTicker(self.extend(request, params))
931
+ data = self.safe_value(response, 'data', [])
932
+ first = self.safe_value(data, 0, {})
933
+ #
934
+ # {
935
+ # "code": "0",
936
+ # "msg": "",
937
+ # "data": [
938
+ # {
939
+ # "instType": "SPOT",
940
+ # "instId": "ETH-BTC",
941
+ # "last": "0.07319",
942
+ # "lastSz": "0.044378",
943
+ # "askPx": "0.07322",
944
+ # "askSz": "4.2",
945
+ # "bidPx": "0.0732",
946
+ # "bidSz": "6.050058",
947
+ # "open24h": "0.07801",
948
+ # "high24h": "0.07975",
949
+ # "low24h": "0.06019",
950
+ # "volCcy24h": "11788.887619",
951
+ # "vol24h": "167493.829229",
952
+ # "ts": "1621440583784",
953
+ # "sodUtc0": "0.07872",
954
+ # "sodUtc8": "0.07345"
955
+ # }
956
+ # ]
957
+ # }
958
+ #
959
+ return self.parse_ticker(first, market)
960
+
961
+ def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
962
+ """
963
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-tickers
964
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
965
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
966
+ :param dict [params]: extra parameters specific to the exchange API endpoint
967
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
968
+ """
969
+ symbols = self.market_symbols(symbols)
970
+ request: dict = {
971
+ 'instType': 'SPOT',
972
+ }
973
+ response = self.publicGetMarketTickers(self.extend(request, params))
974
+ data = self.safe_list(response, 'data', [])
975
+ return self.parse_tickers(data, symbols, params)
976
+
977
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
978
+ #
979
+ # public fetchTrades
980
+ #
981
+ # {
982
+ # "instId": "ETH-BTC",
983
+ # "side": "sell",
984
+ # "sz": "0.119501",
985
+ # "px": "0.07065",
986
+ # "tradeId": "15826757",
987
+ # "ts": "1621446178316"
988
+ # }
989
+ #
990
+ # private fetchMyTrades
991
+ #
992
+ # {
993
+ # "side": "buy",
994
+ # "fillSz": "0.007533",
995
+ # "fillPx": "2654.98",
996
+ # "fee": "-0.000007533",
997
+ # "ordId": "317321390244397056",
998
+ # "instType": "SPOT",
999
+ # "instId": "ETH-USDT",
1000
+ # "clOrdId": "",
1001
+ # "posSide": "net",
1002
+ # "billId": "317321390265368576",
1003
+ # "tag": "0",
1004
+ # "execType": "T",
1005
+ # "tradeId": "107601752",
1006
+ # "feeCcy": "ETH",
1007
+ # "ts": "1621927314985"
1008
+ # }
1009
+ #
1010
+ id = self.safe_string(trade, 'tradeId')
1011
+ marketId = self.safe_string(trade, 'instId')
1012
+ market = self.safe_market(marketId, market, '-')
1013
+ symbol = market['symbol']
1014
+ timestamp = self.safe_integer(trade, 'ts')
1015
+ price = self.safe_string_2(trade, 'fillPx', 'px')
1016
+ amount = self.safe_string_2(trade, 'fillSz', 'sz')
1017
+ side = self.safe_string(trade, 'side')
1018
+ orderId = self.safe_string(trade, 'ordId')
1019
+ feeCostString = self.safe_string(trade, 'fee')
1020
+ fee = None
1021
+ if feeCostString is not None:
1022
+ feeCostSigned = Precise.string_neg(feeCostString)
1023
+ feeCurrencyId = self.safe_string(trade, 'feeCcy')
1024
+ feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1025
+ fee = {
1026
+ 'cost': feeCostSigned,
1027
+ 'currency': feeCurrencyCode,
1028
+ }
1029
+ takerOrMaker = self.safe_string(trade, 'execType')
1030
+ if takerOrMaker == 'T':
1031
+ takerOrMaker = 'taker'
1032
+ elif takerOrMaker == 'M':
1033
+ takerOrMaker = 'maker'
1034
+ return self.safe_trade({
1035
+ 'info': trade,
1036
+ 'timestamp': timestamp,
1037
+ 'datetime': self.iso8601(timestamp),
1038
+ 'symbol': symbol,
1039
+ 'id': id,
1040
+ 'order': orderId,
1041
+ 'type': None,
1042
+ 'takerOrMaker': takerOrMaker,
1043
+ 'side': side,
1044
+ 'price': price,
1045
+ 'amount': amount,
1046
+ 'cost': None,
1047
+ 'fee': fee,
1048
+ }, market)
1049
+
1050
+ def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1051
+ """
1052
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-trades
1053
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-trades-history
1054
+ get the list of most recent trades for a particular symbol
1055
+ :param str symbol: unified symbol of the market to fetch trades for
1056
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1057
+ :param int [limit]: the maximum amount of trades to fetch
1058
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1059
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1060
+ """
1061
+ self.load_markets()
1062
+ market = self.market(symbol)
1063
+ if (limit is None) or (limit > 100):
1064
+ limit = 100 # maximum = default = 100
1065
+ request: dict = {
1066
+ 'instId': market['id'],
1067
+ }
1068
+ method = None
1069
+ method, params = self.handle_option_and_params(params, 'fetchTrades', 'method', 'publicGetMarketTrades')
1070
+ response = None
1071
+ if method == 'publicGetMarketTrades':
1072
+ response = self.publicGetMarketTrades(self.extend(request, params))
1073
+ else:
1074
+ response = self.publicGetMarketHistoryTrades(self.extend(request, params))
1075
+ data = self.safe_list(response, 'data', [])
1076
+ return self.parse_trades(data, market, since, limit)
1077
+
1078
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1079
+ #
1080
+ # [
1081
+ # "1678928760000", # timestamp
1082
+ # "24341.4", # open
1083
+ # "24344", # high
1084
+ # "24313.2", # low
1085
+ # "24323", # close
1086
+ # "628", # contract volume
1087
+ # "2.5819", # base volume
1088
+ # "62800", # quote volume
1089
+ # "0" # candlestick state
1090
+ # ]
1091
+ #
1092
+ return [
1093
+ self.safe_integer(ohlcv, 0),
1094
+ self.safe_number(ohlcv, 1),
1095
+ self.safe_number(ohlcv, 2),
1096
+ self.safe_number(ohlcv, 3),
1097
+ self.safe_number(ohlcv, 4),
1098
+ self.safe_number(ohlcv, 5),
1099
+ ]
1100
+
1101
+ def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1102
+ """
1103
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-candlesticks
1104
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history
1105
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1106
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1107
+ :param str timeframe: the length of time each candle represents
1108
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1109
+ :param int [limit]: the maximum amount of candles to fetch
1110
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1111
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1112
+ """
1113
+ self.load_markets()
1114
+ market = self.market(symbol)
1115
+ duration = self.parse_timeframe(timeframe)
1116
+ options = self.safe_value(self.options, 'fetchOHLCV', {})
1117
+ bar = self.safe_string(self.timeframes, timeframe, timeframe)
1118
+ timezone = self.safe_string(options, 'timezone', 'UTC')
1119
+ if (timezone == 'UTC') and (duration >= 21600): # if utc and timeframe >= 6h
1120
+ bar += timezone.lower()
1121
+ request: dict = {
1122
+ 'instId': market['id'],
1123
+ 'bar': bar,
1124
+ }
1125
+ if limit is not None:
1126
+ request['limit'] = limit # default 100, max 100
1127
+ method = None
1128
+ method, params = self.handle_option_and_params(params, 'fetchOHLCV', 'method', 'publicGetMarketCandles')
1129
+ response = None
1130
+ if method == 'publicGetMarketCandles':
1131
+ response = self.publicGetMarketCandles(self.extend(request, params))
1132
+ else:
1133
+ response = self.publicGetMarketHistoryCandles(self.extend(request, params))
1134
+ data = self.safe_list(response, 'data', [])
1135
+ return self.parse_ohlcvs(data, market, timeframe, since, limit)
1136
+
1137
+ def parse_account_balance(self, response):
1138
+ #
1139
+ # account
1140
+ #
1141
+ # [
1142
+ # {
1143
+ # "balance": 0,
1144
+ # "available": 0,
1145
+ # "currency": "BTC",
1146
+ # "hold": 0
1147
+ # },
1148
+ # {
1149
+ # "balance": 0,
1150
+ # "available": 0,
1151
+ # "currency": "ETH",
1152
+ # "hold": 0
1153
+ # }
1154
+ # ]
1155
+ #
1156
+ # spot
1157
+ #
1158
+ # [
1159
+ # {
1160
+ # "frozen": "0",
1161
+ # "hold": "0",
1162
+ # "id": "2149632",
1163
+ # "currency": "BTC",
1164
+ # "balance": "0.0000000497717339",
1165
+ # "available": "0.0000000497717339",
1166
+ # "holds": "0"
1167
+ # },
1168
+ # {
1169
+ # "frozen": "0",
1170
+ # "hold": "0",
1171
+ # "id": "2149632",
1172
+ # "currency": "ICN",
1173
+ # "balance": "0.00000000925",
1174
+ # "available": "0.00000000925",
1175
+ # "holds": "0"
1176
+ # }
1177
+ # ]
1178
+ #
1179
+ result: dict = {
1180
+ 'info': response,
1181
+ 'timestamp': None,
1182
+ 'datetime': None,
1183
+ }
1184
+ for i in range(0, len(response)):
1185
+ balance = response[i]
1186
+ currencyId = self.safe_string(balance, 'currency')
1187
+ code = self.safe_currency_code(currencyId)
1188
+ account = self.account()
1189
+ account['total'] = self.safe_string(balance, 'balance')
1190
+ account['used'] = self.safe_string(balance, 'hold')
1191
+ account['free'] = self.safe_string(balance, 'available')
1192
+ result[code] = account
1193
+ return self.safe_balance(result)
1194
+
1195
+ def fetch_balance(self, params={}) -> Balances:
1196
+ """
1197
+ query for balance and get the amount of funds available for trading or funds locked in orders
1198
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1199
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1200
+ """
1201
+ self.load_markets()
1202
+ marketType, query = self.handle_market_type_and_params('fetchBalance', None, params)
1203
+ request: dict = {
1204
+ # 'ccy': 'BTC,ETH', # comma-separated list of currency ids
1205
+ }
1206
+ response = None
1207
+ if marketType == 'funding':
1208
+ response = self.privateGetAssetBalances(self.extend(request, query))
1209
+ else:
1210
+ response = self.privateGetAccountBalance(self.extend(request, query))
1211
+ #
1212
+ # {
1213
+ # "code": "0",
1214
+ # "data": [
1215
+ # {
1216
+ # "category": "1",
1217
+ # "delivery": "",
1218
+ # "exercise": "",
1219
+ # "instType": "SPOT",
1220
+ # "level": "Lv1",
1221
+ # "maker": "-0.0008",
1222
+ # "taker": "-0.001",
1223
+ # "ts": "1639043138472"
1224
+ # }
1225
+ # ],
1226
+ # "msg": ""
1227
+ # }
1228
+ #
1229
+ if marketType == 'funding':
1230
+ return self.parse_funding_balance(response)
1231
+ else:
1232
+ return self.parse_trading_balance(response)
1233
+
1234
+ def parse_trading_balance(self, response):
1235
+ result: dict = {'info': response}
1236
+ data = self.safe_value(response, 'data', [])
1237
+ first = self.safe_value(data, 0, {})
1238
+ timestamp = self.safe_integer(first, 'uTime')
1239
+ details = self.safe_value(first, 'details', [])
1240
+ for i in range(0, len(details)):
1241
+ balance = details[i]
1242
+ currencyId = self.safe_string(balance, 'ccy')
1243
+ code = self.safe_currency_code(currencyId)
1244
+ account = self.account()
1245
+ # it may be incorrect to use total, free and used for swap accounts
1246
+ eq = self.safe_string(balance, 'eq')
1247
+ availEq = self.safe_string(balance, 'availEq')
1248
+ if (eq is None) or (availEq is None):
1249
+ account['free'] = self.safe_string(balance, 'availBal')
1250
+ account['used'] = self.safe_string(balance, 'frozenBal')
1251
+ else:
1252
+ account['total'] = eq
1253
+ account['free'] = availEq
1254
+ result[code] = account
1255
+ result['timestamp'] = timestamp
1256
+ result['datetime'] = self.iso8601(timestamp)
1257
+ return self.safe_balance(result)
1258
+
1259
+ def parse_funding_balance(self, response):
1260
+ result: dict = {'info': response}
1261
+ data = self.safe_value(response, 'data', [])
1262
+ for i in range(0, len(data)):
1263
+ balance = data[i]
1264
+ currencyId = self.safe_string(balance, 'ccy')
1265
+ code = self.safe_currency_code(currencyId)
1266
+ account = self.account()
1267
+ # it may be incorrect to use total, free and used for swap accounts
1268
+ account['total'] = self.safe_string(balance, 'bal')
1269
+ account['free'] = self.safe_string(balance, 'availBal')
1270
+ account['used'] = self.safe_string(balance, 'frozenBal')
1271
+ result[code] = account
1272
+ return self.safe_balance(result)
1273
+
1274
+ def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1275
+ """
1276
+ create a market buy order by providing the symbol and cost
1277
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-order
1278
+ :param str symbol: unified symbol of the market to create an order in
1279
+ :param float cost: how much you want to trade in units of the quote currency
1280
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1281
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1282
+ """
1283
+ self.load_markets()
1284
+ market = self.market(symbol)
1285
+ if not market['spot']:
1286
+ raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
1287
+ params['createMarketBuyOrderRequiresPrice'] = False
1288
+ params['tgtCcy'] = 'quote_ccy'
1289
+ return self.create_order(symbol, 'market', 'buy', cost, None, params)
1290
+
1291
+ def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1292
+ """
1293
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-order
1294
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-algo-order
1295
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-multiple-orders
1296
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-advance-algo-order
1297
+ create a trade order
1298
+ :param str symbol: unified symbol of the market to create an order in
1299
+ :param str type: 'market' or 'limit'
1300
+ :param str side: 'buy' or 'sell'
1301
+ :param float amount: how much of currency you want to trade in units of base currency
1302
+ :param float price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1303
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1304
+ :param bool [params.reduceOnly]: MARGIN orders only, or swap/future orders in net mode
1305
+ :param bool [params.postOnly]: True to place a post only order
1306
+ :param float [params.triggerPrice]: conditional orders only, the price at which the order is to be triggered
1307
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered(perpetual swap markets only)
1308
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
1309
+ :param float [params.takeProfit.price]: used for take profit limit orders, not used for take profit market price orders
1310
+ :param str [params.takeProfit.type]: 'market' or 'limit' used to specify the take profit price type
1311
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered(perpetual swap markets only)
1312
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
1313
+ :param float [params.stopLoss.price]: used for stop loss limit orders, not used for stop loss market price orders
1314
+ :param str [params.stopLoss.type]: 'market' or 'limit' used to specify the stop loss price type
1315
+ :param float [params.cost]: *spot market buy only* the quote quantity that can be used alternative for the amount
1316
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1317
+ """
1318
+ self.load_markets()
1319
+ market = self.market(symbol)
1320
+ request = self.create_order_request(symbol, type, side, amount, price, params)
1321
+ method = self.safe_string(self.options, 'createOrder', 'privatePostTradeBatchOrders')
1322
+ requestOrdType = self.safe_string(request, 'ordType')
1323
+ if (requestOrdType == 'trigger') or (requestOrdType == 'conditional') or (type == 'oco') or (type == 'move_order_stop') or (type == 'iceberg') or (type == 'twap'):
1324
+ method = 'privatePostTradeOrderAlgo'
1325
+ if method == 'privatePostTradeBatchOrders':
1326
+ # keep the request body the same
1327
+ # submit a single order in an array to the batch order endpoint
1328
+ # because it has a lower ratelimit
1329
+ request = [request]
1330
+ response = None
1331
+ if method == 'privatePostTradeOrder':
1332
+ response = self.privatePostTradeOrder(request)
1333
+ elif method == 'privatePostTradeOrderAlgo':
1334
+ response = self.privatePostTradeOrderAlgo(request)
1335
+ elif method == 'privatePostTradeBatchOrders':
1336
+ response = self.privatePostTradeBatchOrders(request)
1337
+ else:
1338
+ raise ExchangeError(self.id + ' createOrder() self.options["createOrder"] must be either privatePostTradeBatchOrders or privatePostTradeOrder or privatePostTradeOrderAlgo')
1339
+ data = self.safe_value(response, 'data', [])
1340
+ first = self.safe_value(data, 0)
1341
+ order = self.parse_order(first, market)
1342
+ order['type'] = type
1343
+ order['side'] = side
1344
+ return order
1345
+
1346
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1347
+ market = self.market(symbol)
1348
+ request: dict = {
1349
+ 'instId': market['id'],
1350
+ # 'ccy': currency['id'], # only applicable to cross MARGIN orders in single-currency margin
1351
+ # 'clOrdId': clientOrderId, # up to 32 characters, must be unique
1352
+ # 'tag': tag, # up to 8 characters
1353
+ 'side': side,
1354
+ # 'posSide': 'long', # long, short, # required in the long/short mode, and can only be long or short(only for future or swap)
1355
+ 'ordType': type,
1356
+ # 'ordType': type, # privatePostTradeOrder: market, limit, post_only, fok, ioc, optimal_limit_ioc
1357
+ # 'ordType': type, # privatePostTradeOrderAlgo: conditional, oco, trigger, move_order_stop, iceberg, twap
1358
+ # 'sz': self.amount_to_precision(symbol, amount),
1359
+ # 'px': self.price_to_precision(symbol, price), # limit orders only
1360
+ # 'reduceOnly': False,
1361
+ #
1362
+ # 'triggerPx': 10, # stopPrice(trigger orders)
1363
+ # 'orderPx': 10, # Order price if -1, the order will be executed at the market price.(trigger orders)
1364
+ # 'triggerPxType': 'last', # Conditional default is last, mark or index(trigger orders)
1365
+ #
1366
+ # 'tpTriggerPx': 10, # takeProfitPrice(conditional orders)
1367
+ # 'tpTriggerPxType': 'last', # Conditional default is last, mark or index(conditional orders)
1368
+ # 'tpOrdPx': 10, # Order price for Take-Profit orders, if -1 will be executed at market price(conditional orders)
1369
+ #
1370
+ # 'slTriggerPx': 10, # stopLossPrice(conditional orders)
1371
+ # 'slTriggerPxType': 'last', # Conditional default is last, mark or index(conditional orders)
1372
+ # 'slOrdPx': 10, # Order price for Stop-Loss orders, if -1 will be executed at market price(conditional orders)
1373
+ }
1374
+ triggerPrice = self.safe_value_n(params, ['triggerPrice', 'stopPrice', 'triggerPx'])
1375
+ timeInForce = self.safe_string(params, 'timeInForce', 'GTC')
1376
+ takeProfitPrice = self.safe_value_2(params, 'takeProfitPrice', 'tpTriggerPx')
1377
+ tpOrdPx = self.safe_value(params, 'tpOrdPx', price)
1378
+ tpTriggerPxType = self.safe_string(params, 'tpTriggerPxType', 'last')
1379
+ stopLossPrice = self.safe_value_2(params, 'stopLossPrice', 'slTriggerPx')
1380
+ slOrdPx = self.safe_value(params, 'slOrdPx', price)
1381
+ slTriggerPxType = self.safe_string(params, 'slTriggerPxType', 'last')
1382
+ clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
1383
+ stopLoss = self.safe_value(params, 'stopLoss')
1384
+ stopLossDefined = (stopLoss is not None)
1385
+ takeProfit = self.safe_value(params, 'takeProfit')
1386
+ takeProfitDefined = (takeProfit is not None)
1387
+ defaultMarginMode = self.safe_string_2(self.options, 'defaultMarginMode', 'marginMode', 'cross')
1388
+ marginMode = self.safe_string_2(params, 'marginMode', 'tdMode') # cross or isolated, tdMode not ommited so be extended into the request
1389
+ margin = False
1390
+ if (marginMode is not None) and (marginMode != 'cash'):
1391
+ margin = True
1392
+ else:
1393
+ marginMode = defaultMarginMode
1394
+ margin = self.safe_bool(params, 'margin', False)
1395
+ if margin:
1396
+ defaultCurrency = market['quote'] if (side == 'buy') else market['base']
1397
+ currency = self.safe_string(params, 'ccy', defaultCurrency)
1398
+ request['ccy'] = self.safe_currency_code(currency)
1399
+ tradeMode = marginMode if margin else 'cash'
1400
+ request['tdMode'] = tradeMode
1401
+ isMarketOrder = type == 'market'
1402
+ postOnly = False
1403
+ postOnly, params = self.handle_post_only(isMarketOrder, type == 'post_only', params)
1404
+ params = self.omit(params, ['currency', 'ccy', 'marginMode', 'timeInForce', 'stopPrice', 'triggerPrice', 'clientOrderId', 'stopLossPrice', 'takeProfitPrice', 'slOrdPx', 'tpOrdPx', 'margin', 'stopLoss', 'takeProfit'])
1405
+ ioc = (timeInForce == 'IOC') or (type == 'ioc')
1406
+ fok = (timeInForce == 'FOK') or (type == 'fok')
1407
+ trigger = (triggerPrice is not None) or (type == 'trigger')
1408
+ conditional = (stopLossPrice is not None) or (takeProfitPrice is not None) or (type == 'conditional')
1409
+ marketIOC = (isMarketOrder and ioc) or (type == 'optimal_limit_ioc')
1410
+ defaultTgtCcy = self.safe_string(self.options, 'tgtCcy', 'base_ccy')
1411
+ tgtCcy = self.safe_string(params, 'tgtCcy', defaultTgtCcy)
1412
+ if (not margin):
1413
+ request['tgtCcy'] = tgtCcy
1414
+ if isMarketOrder or marketIOC:
1415
+ request['ordType'] = 'market'
1416
+ if side == 'buy':
1417
+ # spot market buy: "sz" can refer either to base currency units or to quote currency units
1418
+ # see documentation: https://www.okx.com/docs-v5/en/#rest-api-trade-place-order
1419
+ if tgtCcy == 'quote_ccy':
1420
+ # quote_ccy: sz refers to units of quote currency
1421
+ quoteAmount = None
1422
+ createMarketBuyOrderRequiresPrice = True
1423
+ createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
1424
+ cost = self.safe_number_2(params, 'cost', 'sz')
1425
+ params = self.omit(params, ['cost', 'sz'])
1426
+ if cost is not None:
1427
+ quoteAmount = self.cost_to_precision(symbol, cost)
1428
+ elif createMarketBuyOrderRequiresPrice:
1429
+ if price is None:
1430
+ raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend(quote quantity) in the amount argument')
1431
+ else:
1432
+ amountString = self.number_to_string(amount)
1433
+ priceString = self.number_to_string(price)
1434
+ costRequest = Precise.string_mul(amountString, priceString)
1435
+ quoteAmount = self.cost_to_precision(symbol, costRequest)
1436
+ else:
1437
+ quoteAmount = self.cost_to_precision(symbol, amount)
1438
+ request['sz'] = quoteAmount
1439
+ else:
1440
+ request['sz'] = self.amount_to_precision(symbol, amount)
1441
+ else:
1442
+ request['sz'] = self.amount_to_precision(symbol, amount)
1443
+ else:
1444
+ request['sz'] = self.amount_to_precision(symbol, amount)
1445
+ if (not trigger) and (not conditional):
1446
+ request['px'] = self.price_to_precision(symbol, price)
1447
+ if postOnly:
1448
+ request['ordType'] = 'post_only'
1449
+ elif ioc and not marketIOC:
1450
+ request['ordType'] = 'ioc'
1451
+ elif fok:
1452
+ request['ordType'] = 'fok'
1453
+ elif stopLossDefined or takeProfitDefined:
1454
+ if stopLossDefined:
1455
+ stopLossTriggerPrice = self.safe_value_n(stopLoss, ['triggerPrice', 'stopPrice', 'slTriggerPx'])
1456
+ if stopLossTriggerPrice is None:
1457
+ raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["stopLoss"]["triggerPrice"], or params["stopLoss"]["stopPrice"], or params["stopLoss"]["slTriggerPx"] for a stop loss order')
1458
+ request['slTriggerPx'] = self.price_to_precision(symbol, stopLossTriggerPrice)
1459
+ stopLossLimitPrice = self.safe_value_n(stopLoss, ['price', 'stopLossPrice', 'slOrdPx'])
1460
+ stopLossOrderType = self.safe_string(stopLoss, 'type')
1461
+ if stopLossOrderType is not None:
1462
+ stopLossLimitOrderType = (stopLossOrderType == 'limit')
1463
+ stopLossMarketOrderType = (stopLossOrderType == 'market')
1464
+ if (not stopLossLimitOrderType) and (not stopLossMarketOrderType):
1465
+ raise InvalidOrder(self.id + ' createOrder() params["stopLoss"]["type"] must be either "limit" or "market"')
1466
+ elif stopLossLimitOrderType:
1467
+ if stopLossLimitPrice is None:
1468
+ raise InvalidOrder(self.id + ' createOrder() requires a limit price in params["stopLoss"]["price"] or params["stopLoss"]["slOrdPx"] for a stop loss limit order')
1469
+ else:
1470
+ request['slOrdPx'] = self.price_to_precision(symbol, stopLossLimitPrice)
1471
+ elif stopLossOrderType == 'market':
1472
+ request['slOrdPx'] = '-1'
1473
+ elif stopLossLimitPrice is not None:
1474
+ request['slOrdPx'] = self.price_to_precision(symbol, stopLossLimitPrice) # limit sl order
1475
+ else:
1476
+ request['slOrdPx'] = '-1' # market sl order
1477
+ stopLossTriggerPriceType = self.safe_string_2(stopLoss, 'triggerPriceType', 'slTriggerPxType', 'last')
1478
+ if stopLossTriggerPriceType is not None:
1479
+ if (stopLossTriggerPriceType != 'last') and (stopLossTriggerPriceType != 'index') and (stopLossTriggerPriceType != 'mark'):
1480
+ raise InvalidOrder(self.id + ' createOrder() stop loss trigger price type must be one of "last", "index" or "mark"')
1481
+ request['slTriggerPxType'] = stopLossTriggerPriceType
1482
+ if takeProfitDefined:
1483
+ takeProfitTriggerPrice = self.safe_value_n(takeProfit, ['triggerPrice', 'stopPrice', 'tpTriggerPx'])
1484
+ if takeProfitTriggerPrice is None:
1485
+ raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["takeProfit"]["triggerPrice"], or params["takeProfit"]["stopPrice"], or params["takeProfit"]["tpTriggerPx"] for a take profit order')
1486
+ request['tpTriggerPx'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
1487
+ takeProfitLimitPrice = self.safe_value_n(takeProfit, ['price', 'takeProfitPrice', 'tpOrdPx'])
1488
+ takeProfitOrderType = self.safe_string(takeProfit, 'type')
1489
+ if takeProfitOrderType is not None:
1490
+ takeProfitLimitOrderType = (takeProfitOrderType == 'limit')
1491
+ takeProfitMarketOrderType = (takeProfitOrderType == 'market')
1492
+ if (not takeProfitLimitOrderType) and (not takeProfitMarketOrderType):
1493
+ raise InvalidOrder(self.id + ' createOrder() params["takeProfit"]["type"] must be either "limit" or "market"')
1494
+ elif takeProfitLimitOrderType:
1495
+ if takeProfitLimitPrice is None:
1496
+ raise InvalidOrder(self.id + ' createOrder() requires a limit price in params["takeProfit"]["price"] or params["takeProfit"]["tpOrdPx"] for a take profit limit order')
1497
+ else:
1498
+ request['tpOrdPx'] = self.price_to_precision(symbol, takeProfitLimitPrice)
1499
+ elif takeProfitOrderType == 'market':
1500
+ request['tpOrdPx'] = '-1'
1501
+ elif takeProfitLimitPrice is not None:
1502
+ request['tpOrdPx'] = self.price_to_precision(symbol, takeProfitLimitPrice) # limit tp order
1503
+ else:
1504
+ request['tpOrdPx'] = '-1' # market tp order
1505
+ takeProfitTriggerPriceType = self.safe_string_2(takeProfit, 'triggerPriceType', 'tpTriggerPxType', 'last')
1506
+ if takeProfitTriggerPriceType is not None:
1507
+ if (takeProfitTriggerPriceType != 'last') and (takeProfitTriggerPriceType != 'index') and (takeProfitTriggerPriceType != 'mark'):
1508
+ raise InvalidOrder(self.id + ' createOrder() take profit trigger price type must be one of "last", "index" or "mark"')
1509
+ request['tpTriggerPxType'] = takeProfitTriggerPriceType
1510
+ elif trigger:
1511
+ request['ordType'] = 'trigger'
1512
+ request['triggerPx'] = self.price_to_precision(symbol, triggerPrice)
1513
+ request['orderPx'] = '-1' if isMarketOrder else self.price_to_precision(symbol, price)
1514
+ elif conditional:
1515
+ request['ordType'] = 'conditional'
1516
+ twoWayCondition = ((takeProfitPrice is not None) and (stopLossPrice is not None))
1517
+ # if TP and SL are sent together
1518
+ # 'conditional' only stop-loss order will be applied
1519
+ if twoWayCondition:
1520
+ request['ordType'] = 'oco'
1521
+ if takeProfitPrice is not None:
1522
+ request['tpTriggerPx'] = self.price_to_precision(symbol, takeProfitPrice)
1523
+ request['tpOrdPx'] = '-1' if (tpOrdPx is None) else self.price_to_precision(symbol, tpOrdPx)
1524
+ request['tpTriggerPxType'] = tpTriggerPxType
1525
+ if stopLossPrice is not None:
1526
+ request['slTriggerPx'] = self.price_to_precision(symbol, stopLossPrice)
1527
+ request['slOrdPx'] = '-1' if (slOrdPx is None) else self.price_to_precision(symbol, slOrdPx)
1528
+ request['slTriggerPxType'] = slTriggerPxType
1529
+ if clientOrderId is None:
1530
+ brokerId = self.safe_string(self.options, 'brokerId')
1531
+ if brokerId is not None:
1532
+ request['clOrdId'] = brokerId + self.uuid16()
1533
+ request['tag'] = brokerId
1534
+ else:
1535
+ request['clOrdId'] = clientOrderId
1536
+ params = self.omit(params, ['clOrdId', 'clientOrderId'])
1537
+ return self.extend(request, params)
1538
+
1539
+ def cancel_order(self, id: str, symbol: Str = None, params={}):
1540
+ """
1541
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-order
1542
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-algo-order
1543
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-advance-algo-order
1544
+ cancels an open order
1545
+ :param str id: order id
1546
+ :param str symbol: unified symbol of the market the order was made in
1547
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1548
+ :param bool [params.stop]: True if cancel trigger or conditional orders
1549
+ :param bool [params.advanced]: True if canceling advanced orders only
1550
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1551
+ """
1552
+ if symbol is None:
1553
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
1554
+ self.load_markets()
1555
+ stop = self.safe_value_2(params, 'stop', 'trigger')
1556
+ advanced = self.safe_value(params, 'advanced')
1557
+ if stop or advanced:
1558
+ orderInner = self.cancel_orders([id], symbol, params)
1559
+ return self.safe_value(orderInner, 0)
1560
+ market = self.market(symbol)
1561
+ request: dict = {
1562
+ 'instId': market['id'],
1563
+ # 'ordId': id, # either ordId or clOrdId is required
1564
+ # 'clOrdId': clientOrderId,
1565
+ }
1566
+ clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
1567
+ if clientOrderId is not None:
1568
+ request['clOrdId'] = clientOrderId
1569
+ else:
1570
+ request['ordId'] = str(id)
1571
+ query = self.omit(params, ['clOrdId', 'clientOrderId'])
1572
+ response = self.privatePostTradeCancelOrder(self.extend(request, query))
1573
+ # {"code":"0","data":[{"clOrdId":"","ordId":"317251910906576896","sCode":"0","sMsg":""}],"msg":""}
1574
+ data = self.safe_value(response, 'data', [])
1575
+ order = self.safe_dict(data, 0)
1576
+ return self.parse_order(order, market)
1577
+
1578
+ def parse_ids(self, ids):
1579
+ """
1580
+ * @ignore
1581
+ :param string[]|str ids: order ids
1582
+ :returns str[]: list of order ids
1583
+ """
1584
+ if isinstance(ids, str):
1585
+ return ids.split(',')
1586
+ else:
1587
+ return ids
1588
+
1589
+ def cancel_orders(self, ids, symbol: Str = None, params={}):
1590
+ """
1591
+ cancel multiple orders
1592
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-multiple-orders
1593
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-algo-order
1594
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-advance-algo-order
1595
+ :param str[] ids: order ids
1596
+ :param str symbol: unified market symbol
1597
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1598
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1599
+ """
1600
+ if symbol is None:
1601
+ raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
1602
+ self.load_markets()
1603
+ stop = self.safe_value_2(params, 'stop', 'trigger')
1604
+ advanced = self.safe_value(params, 'advanced')
1605
+ params = self.omit(params, ['stop', 'trigger', 'advanced'])
1606
+ market = self.market(symbol)
1607
+ request = []
1608
+ clientOrderIds = self.parse_ids(self.safe_value_2(params, 'clOrdId', 'clientOrderId'))
1609
+ algoIds = self.parse_ids(self.safe_value(params, 'algoId'))
1610
+ if clientOrderIds is None:
1611
+ ids = self.parse_ids(ids)
1612
+ if algoIds is not None:
1613
+ for i in range(0, len(algoIds)):
1614
+ request.append({
1615
+ 'algoId': algoIds[i],
1616
+ 'instId': market['id'],
1617
+ })
1618
+ for i in range(0, len(ids)):
1619
+ if stop or advanced:
1620
+ request.append({
1621
+ 'algoId': ids[i],
1622
+ 'instId': market['id'],
1623
+ })
1624
+ else:
1625
+ request.append({
1626
+ 'ordId': ids[i],
1627
+ 'instId': market['id'],
1628
+ })
1629
+ else:
1630
+ for i in range(0, len(clientOrderIds)):
1631
+ request.append({
1632
+ 'instId': market['id'],
1633
+ 'clOrdId': clientOrderIds[i],
1634
+ })
1635
+ response = None
1636
+ if stop:
1637
+ response = self.privatePostTradeCancelAlgos(request)
1638
+ elif advanced:
1639
+ response = self.privatePostTradeCancelAdvanceAlgos(request)
1640
+ else:
1641
+ response = self.privatePostTradeCancelBatchOrders(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
1642
+ #
1643
+ # {
1644
+ # "code": "0",
1645
+ # "data": [
1646
+ # {
1647
+ # "clOrdId": "e123456789ec4dBC1123456ba123b45e",
1648
+ # "ordId": "405071912345641543",
1649
+ # "sCode": "0",
1650
+ # "sMsg": ""
1651
+ # },
1652
+ # ...
1653
+ # ],
1654
+ # "msg": ""
1655
+ # }
1656
+ #
1657
+ #
1658
+ ordersData = self.safe_list(response, 'data', [])
1659
+ return self.parse_orders(ordersData, market, None, None, params)
1660
+
1661
+ def parse_order_status(self, status: Str):
1662
+ statuses: dict = {
1663
+ 'canceled': 'canceled',
1664
+ 'live': 'open',
1665
+ 'partially_filled': 'open',
1666
+ 'filled': 'closed',
1667
+ 'effective': 'closed',
1668
+ }
1669
+ return self.safe_string(statuses, status, status)
1670
+
1671
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1672
+ #
1673
+ # createOrder
1674
+ #
1675
+ # {
1676
+ # "clOrdId": "oktswap6",
1677
+ # "ordId": "312269865356374016",
1678
+ # "tag": "",
1679
+ # "sCode": "0",
1680
+ # "sMsg": ""
1681
+ # }
1682
+ #
1683
+ # editOrder
1684
+ #
1685
+ # {
1686
+ # "clOrdId": "e847386590ce4dBCc1a045253497a547",
1687
+ # "ordId": "559176536793178112",
1688
+ # "reqId": "",
1689
+ # "sCode": "0",
1690
+ # "sMsg": ""
1691
+ # }
1692
+ #
1693
+ # Spot and Swap fetchOrder, fetchOpenOrders
1694
+ #
1695
+ # {
1696
+ # "accFillSz": "0",
1697
+ # "avgPx": "",
1698
+ # "cTime": "1621910749815",
1699
+ # "category": "normal",
1700
+ # "ccy": "",
1701
+ # "clOrdId": "",
1702
+ # "fee": "0",
1703
+ # "feeCcy": "ETH",
1704
+ # "fillPx": "",
1705
+ # "fillSz": "0",
1706
+ # "fillTime": "",
1707
+ # "instId": "ETH-USDT",
1708
+ # "instType": "SPOT",
1709
+ # "lever": "",
1710
+ # "ordId": "317251910906576896",
1711
+ # "ordType": "limit",
1712
+ # "pnl": "0",
1713
+ # "posSide": "net",
1714
+ # "px": "2000",
1715
+ # "rebate": "0",
1716
+ # "rebateCcy": "USDT",
1717
+ # "side": "buy",
1718
+ # "slOrdPx": "",
1719
+ # "slTriggerPx": "",
1720
+ # "state": "live",
1721
+ # "sz": "0.001",
1722
+ # "tag": "",
1723
+ # "tdMode": "cash",
1724
+ # "tpOrdPx": "",
1725
+ # "tpTriggerPx": "",
1726
+ # "tradeId": "",
1727
+ # "uTime": "1621910749815"
1728
+ # }
1729
+ #
1730
+ # Algo Order fetchOpenOrders, fetchCanceledOrders, fetchClosedOrders
1731
+ #
1732
+ # {
1733
+ # "activePx": "",
1734
+ # "activePxType": "",
1735
+ # "actualPx": "",
1736
+ # "actualSide": "buy",
1737
+ # "actualSz": "0",
1738
+ # "algoId": "431375349042380800",
1739
+ # "cTime": "1649119897778",
1740
+ # "callbackRatio": "",
1741
+ # "callbackSpread": "",
1742
+ # "ccy": "",
1743
+ # "ctVal": "0.01",
1744
+ # "instId": "BTC-USDT-SWAP",
1745
+ # "instType": "SWAP",
1746
+ # "last": "46538.9",
1747
+ # "lever": "125",
1748
+ # "moveTriggerPx": "",
1749
+ # "notionalUsd": "467.059",
1750
+ # "ordId": "",
1751
+ # "ordPx": "50000",
1752
+ # "ordType": "trigger",
1753
+ # "posSide": "long",
1754
+ # "pxLimit": "",
1755
+ # "pxSpread": "",
1756
+ # "pxVar": "",
1757
+ # "side": "buy",
1758
+ # "slOrdPx": "",
1759
+ # "slTriggerPx": "",
1760
+ # "slTriggerPxType": "",
1761
+ # "state": "live",
1762
+ # "sz": "1",
1763
+ # "szLimit": "",
1764
+ # "tag": "",
1765
+ # "tdMode": "isolated",
1766
+ # "tgtCcy": "",
1767
+ # "timeInterval": "",
1768
+ # "tpOrdPx": "",
1769
+ # "tpTriggerPx": "",
1770
+ # "tpTriggerPxType": "",
1771
+ # "triggerPx": "50000",
1772
+ # "triggerPxType": "last",
1773
+ # "triggerTime": "",
1774
+ # "uly": "BTC-USDT"
1775
+ # }
1776
+ #
1777
+ id = self.safe_string_2(order, 'algoId', 'ordId')
1778
+ timestamp = self.safe_integer(order, 'cTime')
1779
+ lastUpdateTimestamp = self.safe_integer(order, 'uTime')
1780
+ lastTradeTimestamp = self.safe_integer(order, 'fillTime')
1781
+ side = self.safe_string(order, 'side')
1782
+ type = self.safe_string(order, 'ordType')
1783
+ postOnly = None
1784
+ timeInForce = None
1785
+ if type == 'post_only':
1786
+ postOnly = True
1787
+ type = 'limit'
1788
+ elif type == 'fok':
1789
+ timeInForce = 'FOK'
1790
+ type = 'limit'
1791
+ elif type == 'ioc':
1792
+ timeInForce = 'IOC'
1793
+ type = 'limit'
1794
+ marketId = self.safe_string(order, 'instId')
1795
+ market = self.safe_market(marketId, market)
1796
+ symbol = self.safe_symbol(marketId, market, '-')
1797
+ filled = self.safe_string(order, 'accFillSz')
1798
+ price = self.safe_string_2(order, 'px', 'ordPx')
1799
+ average = self.safe_string(order, 'avgPx')
1800
+ status = self.parse_order_status(self.safe_string(order, 'state'))
1801
+ feeCostString = self.safe_string(order, 'fee')
1802
+ amount = None
1803
+ cost = None
1804
+ # spot market buy: "sz" can refer either to base currency units or to quote currency units
1805
+ # see documentation: https://www.okx.com/docs-v5/en/#rest-api-trade-place-order
1806
+ defaultTgtCcy = self.safe_string(self.options, 'tgtCcy', 'base_ccy')
1807
+ tgtCcy = self.safe_string(order, 'tgtCcy', defaultTgtCcy)
1808
+ if (side == 'buy') and (type == 'market') and (tgtCcy == 'quote_ccy'):
1809
+ # "sz" refers to the cost
1810
+ cost = self.safe_string(order, 'sz')
1811
+ else:
1812
+ # "sz" refers to the trade currency amount
1813
+ amount = self.safe_string(order, 'sz')
1814
+ fee = None
1815
+ if feeCostString is not None:
1816
+ feeCostSigned = Precise.string_neg(feeCostString)
1817
+ feeCurrencyId = self.safe_string(order, 'feeCcy')
1818
+ feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1819
+ fee = {
1820
+ 'cost': self.parse_number(feeCostSigned),
1821
+ 'currency': feeCurrencyCode,
1822
+ }
1823
+ clientOrderId = self.safe_string(order, 'clOrdId')
1824
+ if (clientOrderId is not None) and (len(clientOrderId) < 1):
1825
+ clientOrderId = None # fix empty clientOrderId string
1826
+ stopLossPrice = self.safe_number_2(order, 'slTriggerPx', 'slOrdPx')
1827
+ takeProfitPrice = self.safe_number_2(order, 'tpTriggerPx', 'tpOrdPx')
1828
+ stopPrice = self.safe_number_n(order, ['triggerPx', 'moveTriggerPx'])
1829
+ reduceOnlyRaw = self.safe_string(order, 'reduceOnly')
1830
+ reduceOnly = False
1831
+ if reduceOnly is not None:
1832
+ reduceOnly = (reduceOnlyRaw == 'true')
1833
+ return self.safe_order({
1834
+ 'info': order,
1835
+ 'id': id,
1836
+ 'clientOrderId': clientOrderId,
1837
+ 'timestamp': timestamp,
1838
+ 'datetime': self.iso8601(timestamp),
1839
+ 'lastTradeTimestamp': lastTradeTimestamp,
1840
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
1841
+ 'symbol': symbol,
1842
+ 'type': type,
1843
+ 'timeInForce': timeInForce,
1844
+ 'postOnly': postOnly,
1845
+ 'side': side,
1846
+ 'price': price,
1847
+ 'stopLossPrice': stopLossPrice,
1848
+ 'takeProfitPrice': takeProfitPrice,
1849
+ 'stopPrice': stopPrice,
1850
+ 'triggerPrice': stopPrice,
1851
+ 'average': average,
1852
+ 'cost': cost,
1853
+ 'amount': amount,
1854
+ 'filled': filled,
1855
+ 'remaining': None,
1856
+ 'status': status,
1857
+ 'fee': fee,
1858
+ 'trades': None,
1859
+ 'reduceOnly': reduceOnly,
1860
+ }, market)
1861
+
1862
+ def fetch_order(self, id: str, symbol: Str = None, params={}):
1863
+ """
1864
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-details
1865
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-algo-order-list
1866
+ fetches information on an order made by the user
1867
+ :param str symbol: unified symbol of the market the order was made in
1868
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1869
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1870
+ """
1871
+ if symbol is None:
1872
+ raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
1873
+ self.load_markets()
1874
+ market = self.market(symbol)
1875
+ request: dict = {
1876
+ 'instId': market['id'],
1877
+ # 'clOrdId': 'abcdef12345', # optional, [a-z0-9]{1,32}
1878
+ # 'ordId': id,
1879
+ }
1880
+ clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
1881
+ stop = self.safe_value_2(params, 'stop', 'trigger')
1882
+ if stop:
1883
+ if clientOrderId is not None:
1884
+ request['algoClOrdId'] = clientOrderId
1885
+ else:
1886
+ request['algoId'] = id
1887
+ else:
1888
+ if clientOrderId is not None:
1889
+ request['clOrdId'] = clientOrderId
1890
+ else:
1891
+ request['ordId'] = id
1892
+ query = self.omit(params, ['clientOrderId', 'stop', 'trigger'])
1893
+ response = None
1894
+ if stop:
1895
+ response = self.privateGetTradeOrderAlgo(self.extend(request, query))
1896
+ else:
1897
+ response = self.privateGetTradeOrder(self.extend(request, query))
1898
+ data = self.safe_value(response, 'data', [])
1899
+ order = self.safe_dict(data, 0)
1900
+ return self.parse_order(order)
1901
+
1902
+ def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1903
+ """
1904
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-list
1905
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-algo-order-list
1906
+ fetch all unfilled currently open orders
1907
+ :param str symbol: unified market symbol
1908
+ :param int [since]: the earliest time in ms to fetch open orders for
1909
+ :param int [limit]: the maximum number of open orders structures to retrieve
1910
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1911
+ :param bool [params.stop]: True if fetching trigger or conditional orders
1912
+ :param str [params.ordType]: "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
1913
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1914
+ """
1915
+ self.load_markets()
1916
+ request: dict = {
1917
+ # 'instId': market['id'],
1918
+ # 'ordType': 'limit', # market, limit, post_only, fok, ioc, comma-separated, stop orders: conditional, oco, trigger, move_order_stop, iceberg, or twap
1919
+ # 'state': 'live', # live, partially_filled
1920
+ # 'after': orderId,
1921
+ # 'before': orderId,
1922
+ # 'limit': limit, # default 100, max 100
1923
+ }
1924
+ market = None
1925
+ if symbol is not None:
1926
+ market = self.market(symbol)
1927
+ request['instId'] = market['id']
1928
+ if limit is not None:
1929
+ request['limit'] = limit # default 100, max 100
1930
+ ordType = self.safe_string(params, 'ordType')
1931
+ stop = self.safe_value(params, 'stop') or (self.safe_string(params, 'ordType') is not None)
1932
+ if stop and (ordType is None):
1933
+ request['ordType'] = 'trigger' # default to trigger
1934
+ params = self.omit(params, ['stop'])
1935
+ response = None
1936
+ if stop:
1937
+ response = self.privateGetTradeOrdersAlgoPending(self.extend(request, params))
1938
+ else:
1939
+ response = self.privateGetTradeOrdersPending(self.extend(request, params))
1940
+ data = self.safe_list(response, 'data', [])
1941
+ return self.parse_orders(data, market, since, limit)
1942
+
1943
+ def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1944
+ """
1945
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-algo-order-history
1946
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-history-last-3-months
1947
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-history-last-7-days
1948
+ fetches information on multiple closed orders made by the user
1949
+ :param str symbol: unified market symbol of the market orders were made in
1950
+ :param int [since]: the earliest time in ms to fetch orders for
1951
+ :param int [limit]: the maximum number of order structures to retrieve
1952
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1953
+ :param bool [params.stop]: True if fetching trigger or conditional orders
1954
+ :param str [params.ordType]: "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
1955
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1956
+ """
1957
+ self.load_markets()
1958
+ request: dict = {
1959
+ 'instType': 'SPOT',
1960
+ }
1961
+ market = None
1962
+ if symbol is not None:
1963
+ market = self.market(symbol)
1964
+ request['instId'] = market['id']
1965
+ ordType = self.safe_string(params, 'ordType')
1966
+ stop = self.safe_value(params, 'stop') or (self.safe_string(params, 'ordType') is not None)
1967
+ if stop and (ordType is None):
1968
+ request['ordType'] = 'trigger' # default to trigger
1969
+ params = self.omit(params, ['stop'])
1970
+ response = None
1971
+ if stop:
1972
+ response = self.privateGetTradeOrdersAlgoHistory(self.extend(request, params))
1973
+ else:
1974
+ method = None
1975
+ method, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'method', 'privateGetTradeOrdersHistory')
1976
+ if method == 'privateGetTradeOrdersHistory':
1977
+ response = self.privateGetTradeOrdersHistory(self.extend(request, params))
1978
+ else:
1979
+ response = self.privateGetTradeOrdersHistoryArchive(self.extend(request, params))
1980
+ # {
1981
+ # "code": "0",
1982
+ # "data": [
1983
+ # {
1984
+ # "accFillSz": "0",
1985
+ # "avgPx": "",
1986
+ # "cTime": "1621910749815",
1987
+ # "category": "normal",
1988
+ # "ccy": "",
1989
+ # "clOrdId": "",
1990
+ # "fee": "0",
1991
+ # "feeCcy": "ETH",
1992
+ # "fillPx": "",
1993
+ # "fillSz": "0",
1994
+ # "fillTime": "",
1995
+ # "instId": "ETH-USDT",
1996
+ # "instType": "SPOT",
1997
+ # "lever": "",
1998
+ # "ordId": "317251910906576896",
1999
+ # "ordType": "limit",
2000
+ # "pnl": "0",
2001
+ # "posSide": "net",
2002
+ # "px":"20 00",
2003
+ # "rebate": "0",
2004
+ # "rebateCcy": "USDT",
2005
+ # "side": "buy",
2006
+ # "slOrdPx": "",
2007
+ # "slTriggerPx": "",
2008
+ # "state": "live",
2009
+ # "sz":"0. 001",
2010
+ # "tag": "",
2011
+ # "tdMode": "cash",
2012
+ # "tpOrdPx": "",
2013
+ # "tpTriggerPx": "",
2014
+ # "tradeId": "",
2015
+ # "uTime": "1621910749815"
2016
+ # }
2017
+ # ],
2018
+ # "msg":""
2019
+ # }
2020
+ #
2021
+ data = self.safe_list(response, 'data', [])
2022
+ return self.parse_orders(data, market, since, limit)
2023
+
2024
+ def parse_deposit_address(self, depositAddress, currency: Currency = None):
2025
+ #
2026
+ # {
2027
+ # "addr": "okbtothemoon",
2028
+ # "memo": "971668", # may be missing
2029
+ # "tag":"52055", # may be missing
2030
+ # "pmtId": "", # may be missing
2031
+ # "ccy": "BTC",
2032
+ # "to": "6", # 1 SPOT, 3 FUTURES, 6 FUNDING, 9 SWAP, 12 OPTION, 18 Unified account
2033
+ # "selected": True
2034
+ # }
2035
+ #
2036
+ # {
2037
+ # "ccy":"usdt-erc20",
2038
+ # "to":"6",
2039
+ # "addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa",
2040
+ # "selected":true
2041
+ # }
2042
+ #
2043
+ # {
2044
+ # "chain": "ETH-OKExChain",
2045
+ # "addrEx": {"comment": "6040348"}, # some currencies like TON may have self field,
2046
+ # "ctAddr": "72315c",
2047
+ # "ccy": "ETH",
2048
+ # "to": "6",
2049
+ # "addr": "0x1c9f2244d1ccaa060bd536827c18925db10db102",
2050
+ # "selected": True
2051
+ # }
2052
+ #
2053
+ address = self.safe_string(depositAddress, 'addr')
2054
+ tag = self.safe_string_n(depositAddress, ['tag', 'pmtId', 'memo'])
2055
+ if tag is None:
2056
+ addrEx = self.safe_value(depositAddress, 'addrEx', {})
2057
+ tag = self.safe_string(addrEx, 'comment')
2058
+ currencyId = self.safe_string(depositAddress, 'ccy')
2059
+ currency = self.safe_currency(currencyId, currency)
2060
+ code = currency['code']
2061
+ chain = self.safe_string(depositAddress, 'chain')
2062
+ networkId = chain.replace(currencyId + '-', '')
2063
+ network = self.network_id_to_code(networkId)
2064
+ # inconsistent naming responses from exchange
2065
+ # with respect to network naming provided in currency info vs address chain-names and ids
2066
+ #
2067
+ # response from address endpoint:
2068
+ # {
2069
+ # "chain": "USDT-Polygon",
2070
+ # "ctAddr": "",
2071
+ # "ccy": "USDT",
2072
+ # "to":"6" ,
2073
+ # "addr": "0x1903441e386cc49d937f6302955b5feb4286dcfa",
2074
+ # "selected": True
2075
+ # }
2076
+ # network information from currency['networks'] field:
2077
+ # Polygon: {
2078
+ # "info": {
2079
+ # "canDep": False,
2080
+ # "canInternal": False,
2081
+ # "canWd": False,
2082
+ # "ccy": "USDT",
2083
+ # "chain": "USDT-Polygon-Bridge",
2084
+ # "mainNet": False,
2085
+ # "maxFee": "26.879528",
2086
+ # "minFee": "13.439764",
2087
+ # "minWd": "0.001",
2088
+ # "name": ''
2089
+ # },
2090
+ # "id": "USDT-Polygon-Bridge",
2091
+ # "network": "Polygon",
2092
+ # "active": False,
2093
+ # "deposit": False,
2094
+ # "withdraw": False,
2095
+ # "fee": 13.439764,
2096
+ # "precision": None,
2097
+ # "limits": {
2098
+ # "withdraw": {
2099
+ # "min": 0.001,
2100
+ # "max": None
2101
+ # }
2102
+ # }
2103
+ # },
2104
+ #
2105
+ self.check_address(address)
2106
+ return {
2107
+ 'currency': code,
2108
+ 'address': address,
2109
+ 'tag': tag,
2110
+ 'network': network,
2111
+ 'info': depositAddress,
2112
+ }
2113
+
2114
+ def fetch_deposit_address(self, code: str, params={}):
2115
+ """
2116
+ fetch the deposit address for a currency associated with self account
2117
+ :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
2118
+ :param str code: unified currency code
2119
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2120
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2121
+ """
2122
+ self.load_markets()
2123
+ defaultNetwork = self.safe_string(self.options, 'defaultNetwork', 'ERC20')
2124
+ networkId = self.safe_string(params, 'network', defaultNetwork)
2125
+ networkCode = self.network_id_to_code(networkId)
2126
+ params = self.omit(params, 'network')
2127
+ response = self.fetch_deposit_addresses_by_network(code, params)
2128
+ result = self.safe_value(response, networkCode)
2129
+ if result is None:
2130
+ raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + networkCode + ' deposit address for ' + code)
2131
+ return result
2132
+
2133
+ def fetch_deposit_addresses_by_network(self, code: str, params={}):
2134
+ """
2135
+ fetch a dictionary of addresses for a currency, indexed by network
2136
+ :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
2137
+ :param str code: unified currency code of the currency for the deposit address
2138
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2139
+ :returns dict: a dictionary of `address structures <https://docs.ccxt.com/#/?id=address-structure>` indexed by the network
2140
+ """
2141
+ self.load_markets()
2142
+ currency = self.currency(code)
2143
+ request: dict = {
2144
+ 'ccy': currency['id'],
2145
+ }
2146
+ response = self.privateGetAssetDepositAddress(self.extend(request, params))
2147
+ #
2148
+ # {
2149
+ # "code": "0",
2150
+ # "msg": "",
2151
+ # "data": [
2152
+ # {
2153
+ # "addr": "okbtothemoon",
2154
+ # "memo": "971668", # may be missing
2155
+ # "tag":"52055", # may be missing
2156
+ # "pmtId": "", # may be missing
2157
+ # "ccy": "BTC",
2158
+ # "to": "6", # 1 SPOT, 3 FUTURES, 6 FUNDING, 9 SWAP, 12 OPTION, 18 Unified account
2159
+ # "selected": True
2160
+ # },
2161
+ # # {"ccy":"usdt-erc20","to":"6","addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa","selected":true},
2162
+ # # {"ccy":"usdt-trc20","to":"6","addr":"TRrd5SiSZrfQVRKm4e9SRSbn2LNTYqCjqx","selected":true},
2163
+ # # {"ccy":"usdt_okexchain","to":"6","addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa","selected":true},
2164
+ # # {"ccy":"usdt_kip20","to":"6","addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa","selected":true},
2165
+ # ]
2166
+ # }
2167
+ #
2168
+ data = self.safe_value(response, 'data', [])
2169
+ filtered = self.filter_by(data, 'selected', True)
2170
+ parsed = self.parse_deposit_addresses(filtered, [currency['code']], False)
2171
+ return self.index_by(parsed, 'network')
2172
+
2173
+ def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2174
+ """
2175
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-funds-transfer
2176
+ transfer currency internally between wallets on the same account
2177
+ :param str code: unified currency code
2178
+ :param float amount: amount to transfer
2179
+ :param str fromAccount: account to transfer from
2180
+ :param str toAccount: account to transfer to
2181
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2182
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
2183
+ """
2184
+ self.load_markets()
2185
+ currency = self.currency(code)
2186
+ accountsByType = self.safe_value(self.options, 'accountsByType', {})
2187
+ fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
2188
+ toId = self.safe_string(accountsByType, toAccount, toAccount)
2189
+ request: dict = {
2190
+ 'ccy': currency['id'],
2191
+ 'amt': self.currency_to_precision(code, amount),
2192
+ 'type': '0', # 0 = transfer within account by default, 1 = master account to sub-account, 2 = sub-account to master account, 3 = sub-account to master account(Only applicable to APIKey from sub-account), 4 = sub-account to sub-account
2193
+ 'from': fromId, # remitting account, 6: Funding account, 18: Trading account
2194
+ 'to': toId, # beneficiary account, 6: Funding account, 18: Trading account
2195
+ # 'subAcct': 'sub-account-name', # optional, only required when type is 1, 2 or 4
2196
+ # 'loanTrans': False, # Whether or not borrowed coins can be transferred out under Multi-currency margin and Portfolio margin. The default is False
2197
+ # 'clientId': 'client-supplied id', # A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 32 characters
2198
+ # 'omitPosRisk': False, # Ignore position risk. Default is False. Applicable to Portfolio margin
2199
+ }
2200
+ if fromId == 'master':
2201
+ request['type'] = '1'
2202
+ request['subAcct'] = toId
2203
+ request['from'] = self.safe_string(params, 'from', '6')
2204
+ request['to'] = self.safe_string(params, 'to', '6')
2205
+ elif toId == 'master':
2206
+ request['type'] = '2'
2207
+ request['subAcct'] = fromId
2208
+ request['from'] = self.safe_string(params, 'from', '6')
2209
+ request['to'] = self.safe_string(params, 'to', '6')
2210
+ response = self.privatePostAssetTransfer(self.extend(request, params))
2211
+ #
2212
+ # {
2213
+ # "code": "0",
2214
+ # "msg": "",
2215
+ # "data": [
2216
+ # {
2217
+ # "transId": "754147",
2218
+ # "ccy": "USDT",
2219
+ # "from": "6",
2220
+ # "amt": "0.1",
2221
+ # "to": "18"
2222
+ # }
2223
+ # ]
2224
+ # }
2225
+ #
2226
+ data = self.safe_value(response, 'data', [])
2227
+ rawTransfer = self.safe_dict(data, 0, {})
2228
+ return self.parse_transfer(rawTransfer, currency)
2229
+
2230
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
2231
+ #
2232
+ # transfer
2233
+ #
2234
+ # {
2235
+ # "transId": "754147",
2236
+ # "ccy": "USDT",
2237
+ # "from": "6",
2238
+ # "amt": "0.1",
2239
+ # "to": "18"
2240
+ # }
2241
+ #
2242
+ # fetchTransfer
2243
+ #
2244
+ # {
2245
+ # "amt": "5",
2246
+ # "ccy": "USDT",
2247
+ # "from": "18",
2248
+ # "instId": "",
2249
+ # "state": "success",
2250
+ # "subAcct": "",
2251
+ # "to": "6",
2252
+ # "toInstId": "",
2253
+ # "transId": "464424732",
2254
+ # "type": "0"
2255
+ # }
2256
+ #
2257
+ # fetchTransfers
2258
+ #
2259
+ # {
2260
+ # "bal": "70.6874353780312913",
2261
+ # "balChg": "-4.0000000000000000", # negative means "to funding", positive meand "from funding"
2262
+ # "billId": "588900695232225299",
2263
+ # "ccy": "USDT",
2264
+ # "execType": "",
2265
+ # "fee": "",
2266
+ # "from": "18",
2267
+ # "instId": "",
2268
+ # "instType": "",
2269
+ # "mgnMode": "",
2270
+ # "notes": "To Funding Account",
2271
+ # "ordId": "",
2272
+ # "pnl": "",
2273
+ # "posBal": "",
2274
+ # "posBalChg": "",
2275
+ # "price": "0",
2276
+ # "subType": "12",
2277
+ # "sz": "-4",
2278
+ # "to": "6",
2279
+ # "ts": "1686676866989",
2280
+ # "type": "1"
2281
+ # }
2282
+ #
2283
+ id = self.safe_string_2(transfer, 'transId', 'billId')
2284
+ currencyId = self.safe_string(transfer, 'ccy')
2285
+ code = self.safe_currency_code(currencyId, currency)
2286
+ amount = self.safe_number(transfer, 'amt')
2287
+ fromAccountId = self.safe_string(transfer, 'from')
2288
+ toAccountId = self.safe_string(transfer, 'to')
2289
+ accountsById = self.safe_value(self.options, 'accountsById', {})
2290
+ timestamp = self.safe_integer(transfer, 'ts', self.milliseconds())
2291
+ balanceChange = self.safe_string(transfer, 'sz')
2292
+ if balanceChange is not None:
2293
+ amount = self.parse_number(Precise.string_abs(balanceChange))
2294
+ return {
2295
+ 'info': transfer,
2296
+ 'id': id,
2297
+ 'timestamp': timestamp,
2298
+ 'datetime': self.iso8601(timestamp),
2299
+ 'currency': code,
2300
+ 'amount': amount,
2301
+ 'fromAccount': self.safe_string(accountsById, fromAccountId),
2302
+ 'toAccount': self.safe_string(accountsById, toAccountId),
2303
+ 'status': self.parse_transfer_status(self.safe_string(transfer, 'state')),
2304
+ }
2305
+
2306
+ def parse_transfer_status(self, status: Str) -> Str:
2307
+ statuses: dict = {
2308
+ 'success': 'ok',
2309
+ }
2310
+ return self.safe_string(statuses, status, status)
2311
+
2312
+ def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
2313
+ """
2314
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-withdrawal
2315
+ make a withdrawal
2316
+ :param str code: unified currency code
2317
+ :param float amount: the amount to withdraw
2318
+ :param str address: the address to withdraw to
2319
+ :param str tag:
2320
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2321
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2322
+ """
2323
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
2324
+ self.check_address(address)
2325
+ self.load_markets()
2326
+ currency = self.currency(code)
2327
+ if (tag is not None) and (len(tag) > 0):
2328
+ address = address + ':' + tag
2329
+ request: dict = {
2330
+ 'ccy': currency['id'],
2331
+ 'toAddr': address,
2332
+ 'dest': '4',
2333
+ 'amt': self.number_to_string(amount),
2334
+ }
2335
+ network = self.safe_string(params, 'network') # self line allows the user to specify either ERC20 or ETH
2336
+ if network is not None:
2337
+ networks = self.safe_value(self.options, 'networks', {})
2338
+ network = self.safe_string(networks, network.upper(), network) # handle ETH>ERC20 alias
2339
+ request['chain'] = currency['id'] + '-' + network
2340
+ params = self.omit(params, 'network')
2341
+ fee = self.safe_string(params, 'fee')
2342
+ if fee is None:
2343
+ targetNetwork = self.safe_value(currency['networks'], self.network_id_to_code(network), {})
2344
+ fee = self.safe_string(targetNetwork, 'fee')
2345
+ if fee is None:
2346
+ raise ArgumentsRequired(self.id + ' withdraw() requires a "fee" string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKX are fee-free, please set "0". Withdrawing to external digital asset address requires network transaction fee.')
2347
+ request['fee'] = self.number_to_string(fee) # withdrawals to OKCoin or OKX are fee-free, please set 0
2348
+ response = self.privatePostAssetWithdrawal(self.extend(request, params))
2349
+ #
2350
+ # {
2351
+ # "code": "0",
2352
+ # "msg": "",
2353
+ # "data": [
2354
+ # {
2355
+ # "amt": "0.1",
2356
+ # "wdId": "67485",
2357
+ # "ccy": "BTC"
2358
+ # }
2359
+ # ]
2360
+ # }
2361
+ #
2362
+ data = self.safe_value(response, 'data', [])
2363
+ transaction = self.safe_dict(data, 0)
2364
+ return self.parse_transaction(transaction, currency)
2365
+
2366
+ def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2367
+ """
2368
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-get-deposit-history
2369
+ fetch all deposits made to an account
2370
+ :param str code: unified currency code
2371
+ :param int [since]: the earliest time in ms to fetch deposits for
2372
+ :param int [limit]: the maximum number of deposits structures to retrieve
2373
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2374
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2375
+ """
2376
+ self.load_markets()
2377
+ request: dict = {
2378
+ # 'ccy': currency['id'],
2379
+ # 'state': 2, # 0 waiting for confirmation, 1 deposit credited, 2 deposit successful
2380
+ # 'after': since,
2381
+ # 'before' self.milliseconds(),
2382
+ # 'limit': limit, # default 100, max 100
2383
+ }
2384
+ currency = None
2385
+ if code is not None:
2386
+ currency = self.currency(code)
2387
+ request['ccy'] = currency['id']
2388
+ if since is not None:
2389
+ request['before'] = max(since - 1, 0)
2390
+ if limit is not None:
2391
+ request['limit'] = limit # default 100, max 100
2392
+ request, params = self.handle_until_option('after', request, params)
2393
+ response = self.privateGetAssetDepositHistory(self.extend(request, params))
2394
+ #
2395
+ # {
2396
+ # "code": "0",
2397
+ # "msg": "",
2398
+ # "data": [
2399
+ # {
2400
+ # "amt": "0.01044408",
2401
+ # "txId": "1915737_3_0_0_asset",
2402
+ # "ccy": "BTC",
2403
+ # "from": "13801825426",
2404
+ # "to": "",
2405
+ # "ts": "1597026383085",
2406
+ # "state": "2",
2407
+ # "depId": "4703879"
2408
+ # },
2409
+ # {
2410
+ # "amt": "491.6784211",
2411
+ # "txId": "1744594_3_184_0_asset",
2412
+ # "ccy": "OKB",
2413
+ # "from": "",
2414
+ # "to": "",
2415
+ # "ts": "1597026383085",
2416
+ # "state": "2",
2417
+ # "depId": "4703809"
2418
+ # },
2419
+ # {
2420
+ # "amt": "223.18782496",
2421
+ # "txId": "6d892c669225b1092c780bf0da0c6f912fc7dc8f6b8cc53b003288624c",
2422
+ # "ccy": "USDT",
2423
+ # "from": "",
2424
+ # "to": "39kK4XvgEuM7rX9frgyHoZkWqx4iKu1spD",
2425
+ # "ts": "1597026383085",
2426
+ # "state": "2",
2427
+ # "depId": "4703779"
2428
+ # }
2429
+ # ]
2430
+ # }
2431
+ #
2432
+ data = self.safe_list(response, 'data', [])
2433
+ return self.parse_transactions(data, currency, since, limit, params)
2434
+
2435
+ def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2436
+ """
2437
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-get-withdrawal-history
2438
+ fetch all withdrawals made from an account
2439
+ :param str code: unified currency code
2440
+ :param int [since]: the earliest time in ms to fetch withdrawals for
2441
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
2442
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2443
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2444
+ """
2445
+ self.load_markets()
2446
+ request: dict = {
2447
+ # 'ccy': currency['id'],
2448
+ # 'state': 2, # -3: pending cancel, -2 canceled, -1 failed, 0, pending, 1 sending, 2 sent, 3 awaiting email verification, 4 awaiting manual verification, 5 awaiting identity verification
2449
+ # 'after': since,
2450
+ # 'before': self.milliseconds(),
2451
+ # 'limit': limit, # default 100, max 100
2452
+ }
2453
+ currency = None
2454
+ if code is not None:
2455
+ currency = self.currency(code)
2456
+ request['ccy'] = currency['id']
2457
+ if since is not None:
2458
+ request['before'] = max(since - 1, 0)
2459
+ if limit is not None:
2460
+ request['limit'] = limit # default 100, max 100
2461
+ request, params = self.handle_until_option('after', request, params)
2462
+ response = self.privateGetAssetWithdrawalHistory(self.extend(request, params))
2463
+ #
2464
+ # {
2465
+ # "code": "0",
2466
+ # "msg": "",
2467
+ # "data": [
2468
+ # {
2469
+ # "amt": "0.094",
2470
+ # "wdId": "4703879",
2471
+ # "fee": "0.01000000eth",
2472
+ # "txId": "0x62477bac6509a04512819bb1455e923a60dea5966c7caeaa0b24eb8fb0432b85",
2473
+ # "ccy": "ETH",
2474
+ # "from": "13426335357",
2475
+ # "to": "0xA41446125D0B5b6785f6898c9D67874D763A1519",
2476
+ # "ts": "1597026383085",
2477
+ # "state": "2"
2478
+ # },
2479
+ # {
2480
+ # "amt": "0.01",
2481
+ # "wdId": "4703879",
2482
+ # "fee": "0.00000000btc",
2483
+ # "txId": "",
2484
+ # "ccy": "BTC",
2485
+ # "from": "13426335357",
2486
+ # "to": "13426335357",
2487
+ # "ts": "1597026383085",
2488
+ # "state": "2"
2489
+ # }
2490
+ # ]
2491
+ # }
2492
+ #
2493
+ data = self.safe_list(response, 'data', [])
2494
+ return self.parse_transactions(data, currency, since, limit, params)
2495
+
2496
+ def parse_transaction_status(self, status: Str):
2497
+ #
2498
+ # deposit statuses
2499
+ #
2500
+ # {
2501
+ # "0": "waiting for confirmation",
2502
+ # "1": "confirmation account",
2503
+ # "2": "recharge success"
2504
+ # }
2505
+ #
2506
+ # withdrawal statues
2507
+ #
2508
+ # {
2509
+ # '-3': "pending cancel",
2510
+ # "-2": "cancelled",
2511
+ # "-1": "failed",
2512
+ # "0": "pending",
2513
+ # "1": "sending",
2514
+ # "2": "sent",
2515
+ # "3": "email confirmation",
2516
+ # "4": "manual confirmation",
2517
+ # "5": "awaiting identity confirmation"
2518
+ # }
2519
+ #
2520
+ statuses: dict = {
2521
+ '-3': 'pending',
2522
+ '-2': 'canceled',
2523
+ '-1': 'failed',
2524
+ '0': 'pending',
2525
+ '1': 'pending',
2526
+ '2': 'ok',
2527
+ '3': 'pending',
2528
+ '4': 'pending',
2529
+ '5': 'pending',
2530
+ }
2531
+ return self.safe_string(statuses, status, status)
2532
+
2533
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2534
+ #
2535
+ # withdraw
2536
+ #
2537
+ # {
2538
+ # "amt": "0.1",
2539
+ # "wdId": "67485",
2540
+ # "ccy": "BTC"
2541
+ # }
2542
+ #
2543
+ # fetchWithdrawals
2544
+ #
2545
+ # {
2546
+ # "amt": "0.094",
2547
+ # "wdId": "4703879",
2548
+ # "fee": "0.01000000eth",
2549
+ # "txId": "0x62477bac6509a04512819bb1455e923a60dea5966c7caeaa0b24eb8fb0432b85",
2550
+ # "ccy": "ETH",
2551
+ # "from": "13426335357",
2552
+ # "to": "0xA41446125D0B5b6785f6898c9D67874D763A1519",
2553
+ # "tag",
2554
+ # "pmtId",
2555
+ # "memo",
2556
+ # "ts": "1597026383085",
2557
+ # "state": "2"
2558
+ # }
2559
+ #
2560
+ # fetchDeposits
2561
+ #
2562
+ # {
2563
+ # "amt": "0.01044408",
2564
+ # "txId": "1915737_3_0_0_asset",
2565
+ # "ccy": "BTC",
2566
+ # "from": "13801825426",
2567
+ # "to": "",
2568
+ # "ts": "1597026383085",
2569
+ # "state": "2",
2570
+ # "depId": "4703879"
2571
+ # }
2572
+ #
2573
+ type = None
2574
+ id = None
2575
+ withdrawalId = self.safe_string(transaction, 'wdId')
2576
+ addressFrom = self.safe_string(transaction, 'from')
2577
+ addressTo = self.safe_string(transaction, 'to')
2578
+ address = addressTo
2579
+ tagTo = self.safe_string_2(transaction, 'tag', 'memo')
2580
+ tagTo = self.safe_string_2(transaction, 'pmtId', tagTo)
2581
+ if withdrawalId is not None:
2582
+ type = 'withdrawal'
2583
+ id = withdrawalId
2584
+ else:
2585
+ # the payment_id will appear on new deposits but appears to be removed from the response after 2 months
2586
+ id = self.safe_string(transaction, 'depId')
2587
+ type = 'deposit'
2588
+ currencyId = self.safe_string(transaction, 'ccy')
2589
+ code = self.safe_currency_code(currencyId)
2590
+ amount = self.safe_number(transaction, 'amt')
2591
+ status = self.parse_transaction_status(self.safe_string(transaction, 'state'))
2592
+ txid = self.safe_string(transaction, 'txId')
2593
+ timestamp = self.safe_integer(transaction, 'ts')
2594
+ feeCost = None
2595
+ if type == 'deposit':
2596
+ feeCost = 0
2597
+ else:
2598
+ feeCost = self.safe_number(transaction, 'fee')
2599
+ # todo parse tags
2600
+ return {
2601
+ 'info': transaction,
2602
+ 'id': id,
2603
+ 'currency': code,
2604
+ 'amount': amount,
2605
+ 'network': None,
2606
+ 'addressFrom': addressFrom,
2607
+ 'addressTo': addressTo,
2608
+ 'address': address,
2609
+ 'tagFrom': None,
2610
+ 'tagTo': tagTo,
2611
+ 'tag': tagTo,
2612
+ 'status': status,
2613
+ 'type': type,
2614
+ 'updated': None,
2615
+ 'txid': txid,
2616
+ 'timestamp': timestamp,
2617
+ 'datetime': self.iso8601(timestamp),
2618
+ 'comment': None,
2619
+ 'internal': None,
2620
+ 'fee': {
2621
+ 'currency': code,
2622
+ 'cost': feeCost,
2623
+ },
2624
+ }
2625
+
2626
+ def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2627
+ """
2628
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-days
2629
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-months
2630
+ fetch all trades made by the user
2631
+ :param str symbol: unified market symbol
2632
+ :param int [since]: the earliest time in ms to fetch trades for
2633
+ :param int [limit]: the maximum number of trades structures to retrieve
2634
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2635
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2636
+ """
2637
+ self.load_markets()
2638
+ request: dict = {
2639
+ 'instType': 'SPOT',
2640
+ }
2641
+ if (limit is not None) and (limit > 100):
2642
+ limit = 100
2643
+ market = None
2644
+ if symbol is not None:
2645
+ market = self.market(symbol)
2646
+ request['instId'] = market['id']
2647
+ method = None
2648
+ method, params = self.handle_option_and_params(params, 'fetchMyTrades', 'method', 'privateGetTradeFillsHistory')
2649
+ response = None
2650
+ if method == 'privateGetTradeFillsHistory':
2651
+ response = self.privateGetTradeFillsHistory(self.extend(request, params))
2652
+ else:
2653
+ response = self.privateGetTradeFills(self.extend(request, params))
2654
+ data = self.safe_list(response, 'data', [])
2655
+ return self.parse_trades(data, market, since, limit)
2656
+
2657
+ def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2658
+ """
2659
+ fetch all the trades made from a single order
2660
+ :param str id: order id
2661
+ :param str symbol: unified market symbol
2662
+ :param int [since]: the earliest time in ms to fetch trades for
2663
+ :param int [limit]: the maximum number of trades to retrieve
2664
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2665
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2666
+ """
2667
+ request: dict = {
2668
+ # 'instrument_id': market['id'],
2669
+ 'order_id': id,
2670
+ # 'after': '1', # return the page after the specified page number
2671
+ # 'before': '1', # return the page before the specified page number
2672
+ # 'limit': limit, # optional, number of results per request, default = maximum = 100
2673
+ }
2674
+ return self.fetch_my_trades(symbol, since, limit, self.extend(request, params))
2675
+
2676
+ def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
2677
+ """
2678
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-asset-bills-details
2679
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-account-get-bills-details-last-7-days
2680
+ :see: https://www.okcoin.com/docs-v5/en/#rest-api-account-get-bills-details-last-3-months
2681
+ fetch the history of changes, actions done by the user or operations that altered balance of the user
2682
+ :param str code: unified currency code, default is None
2683
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
2684
+ :param int [limit]: max number of ledger entrys to return, default is None
2685
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2686
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
2687
+ """
2688
+ self.load_markets()
2689
+ method = None
2690
+ method, params = self.handle_option_and_params(params, 'fetchLedger', 'method', 'privateGetAccountBills')
2691
+ request: dict = {
2692
+ # 'instType': None, # 'SPOT', 'MARGIN', 'SWAP', 'FUTURES", 'OPTION'
2693
+ # 'ccy': None, # currency['id'],
2694
+ # 'ctType': None, # 'linear', 'inverse', only applicable to FUTURES/SWAP
2695
+ # 'type': varies depending the 'method' endpoint :
2696
+ # - https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-7-days
2697
+ # - https://www.okx.com/docs-v5/en/#rest-api-funding-asset-bills-details
2698
+ # - https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-3-months
2699
+ # 'after': 'id', # return records earlier than the requested bill id
2700
+ # 'before': 'id', # return records newer than the requested bill id
2701
+ # 'limit': 100, # default 100, max 100
2702
+ }
2703
+ if limit is not None:
2704
+ request['limit'] = limit
2705
+ currency = None
2706
+ if code is not None:
2707
+ currency = self.currency(code)
2708
+ request['ccy'] = currency['id']
2709
+ request, params = self.handle_until_option('end', request, params)
2710
+ response = None
2711
+ if method == 'privateGetAccountBillsArchive':
2712
+ response = self.privateGetAccountBillsArchive(self.extend(request, params))
2713
+ elif method == 'privateGetAssetBills':
2714
+ response = self.privateGetAssetBills(self.extend(request, params))
2715
+ else:
2716
+ response = self.privateGetAccountBills(self.extend(request, params))
2717
+ #
2718
+ # privateGetAccountBills, privateGetAccountBillsArchive
2719
+ #
2720
+ # {
2721
+ # "code": "0",
2722
+ # "msg": "",
2723
+ # "data": [
2724
+ # {
2725
+ # "bal": "0.0000819307998198",
2726
+ # "balChg": "-664.2679586599999802",
2727
+ # "billId": "310394313544966151",
2728
+ # "ccy": "USDT",
2729
+ # "fee": "0",
2730
+ # "from": "",
2731
+ # "instId": "LTC-USDT",
2732
+ # "instType": "SPOT",
2733
+ # "mgnMode": "cross",
2734
+ # "notes": "",
2735
+ # "ordId": "310394313519800320",
2736
+ # "pnl": "0",
2737
+ # "posBal": "0",
2738
+ # "posBalChg": "0",
2739
+ # "subType": "2",
2740
+ # "sz": "664.26795866",
2741
+ # "to": "",
2742
+ # "ts": "1620275771196",
2743
+ # "type": "2"
2744
+ # }
2745
+ # ]
2746
+ # }
2747
+ #
2748
+ # privateGetAssetBills
2749
+ #
2750
+ # {
2751
+ # "code": "0",
2752
+ # "msg": "",
2753
+ # "data": [
2754
+ # {
2755
+ # "billId": "12344",
2756
+ # "ccy": "BTC",
2757
+ # "balChg": "2",
2758
+ # "bal": "12",
2759
+ # "type": "1",
2760
+ # "ts": "1597026383085"
2761
+ # }
2762
+ # ]
2763
+ # }
2764
+ #
2765
+ data = self.safe_value(response, 'data', [])
2766
+ return self.parse_ledger(data, currency, since, limit)
2767
+
2768
+ def parse_ledger_entry_type(self, type):
2769
+ types: dict = {
2770
+ '1': 'transfer', # transfer
2771
+ '2': 'trade', # trade
2772
+ '3': 'trade', # delivery
2773
+ '4': 'rebate', # auto token conversion
2774
+ '5': 'trade', # liquidation
2775
+ '6': 'transfer', # margin transfer
2776
+ '7': 'trade', # interest deduction
2777
+ '8': 'fee', # funding rate
2778
+ '9': 'trade', # adl
2779
+ '10': 'trade', # clawback
2780
+ '11': 'trade', # system token conversion
2781
+ }
2782
+ return self.safe_string(types, type, type)
2783
+
2784
+ def parse_ledger_entry(self, item: dict, currency: Currency = None):
2785
+ #
2786
+ # privateGetAccountBills, privateGetAccountBillsArchive
2787
+ #
2788
+ # {
2789
+ # "bal": "0.0000819307998198",
2790
+ # "balChg": "-664.2679586599999802",
2791
+ # "billId": "310394313544966151",
2792
+ # "ccy": "USDT",
2793
+ # "fee": "0",
2794
+ # "from": "",
2795
+ # "instId": "LTC-USDT",
2796
+ # "instType": "SPOT",
2797
+ # "mgnMode": "cross",
2798
+ # "notes": "",
2799
+ # "ordId": "310394313519800320",
2800
+ # "pnl": "0",
2801
+ # "posBal": "0",
2802
+ # "posBalChg": "0",
2803
+ # "subType": "2",
2804
+ # "sz": "664.26795866",
2805
+ # "to": "",
2806
+ # "ts": "1620275771196",
2807
+ # "type": "2"
2808
+ # }
2809
+ #
2810
+ # privateGetAssetBills
2811
+ #
2812
+ # {
2813
+ # "billId": "12344",
2814
+ # "ccy": "BTC",
2815
+ # "balChg": "2",
2816
+ # "bal": "12",
2817
+ # "type": "1",
2818
+ # "ts": "1597026383085"
2819
+ # }
2820
+ #
2821
+ id = self.safe_string(item, 'billId')
2822
+ account = None
2823
+ referenceId = self.safe_string(item, 'ordId')
2824
+ referenceAccount = None
2825
+ type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
2826
+ code = self.safe_currency_code(self.safe_string(item, 'ccy'), currency)
2827
+ amountString = self.safe_string(item, 'balChg')
2828
+ amount = self.parse_number(amountString)
2829
+ timestamp = self.safe_integer(item, 'ts')
2830
+ feeCostString = self.safe_string(item, 'fee')
2831
+ fee = None
2832
+ if feeCostString is not None:
2833
+ fee = {
2834
+ 'cost': self.parse_number(Precise.string_neg(feeCostString)),
2835
+ 'currency': code,
2836
+ }
2837
+ before = None
2838
+ afterString = self.safe_string(item, 'bal')
2839
+ after = self.parse_number(afterString)
2840
+ status = 'ok'
2841
+ marketId = self.safe_string(item, 'instId')
2842
+ symbol = self.safe_symbol(marketId, None, '-')
2843
+ return {
2844
+ 'id': id,
2845
+ 'info': item,
2846
+ 'timestamp': timestamp,
2847
+ 'datetime': self.iso8601(timestamp),
2848
+ 'account': account,
2849
+ 'referenceId': referenceId,
2850
+ 'referenceAccount': referenceAccount,
2851
+ 'type': type,
2852
+ 'currency': code,
2853
+ 'symbol': symbol,
2854
+ 'amount': amount,
2855
+ 'before': before, # balance before
2856
+ 'after': after, # balance after
2857
+ 'status': status,
2858
+ 'fee': fee,
2859
+ }
2860
+
2861
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2862
+ isArray = isinstance(params, list)
2863
+ request = '/api/' + self.version + '/' + self.implode_params(path, params)
2864
+ query = self.omit(params, self.extract_params(path))
2865
+ url = self.implode_hostname(self.urls['api']['rest']) + request
2866
+ if api == 'public':
2867
+ if query:
2868
+ url += '?' + self.urlencode(query)
2869
+ elif api == 'private':
2870
+ self.check_required_credentials()
2871
+ timestamp = self.iso8601(self.milliseconds())
2872
+ headers = {
2873
+ 'OK-ACCESS-KEY': self.apiKey,
2874
+ 'OK-ACCESS-PASSPHRASE': self.password,
2875
+ 'OK-ACCESS-TIMESTAMP': timestamp,
2876
+ # 'OK-FROM': '',
2877
+ # 'OK-TO': '',
2878
+ # 'OK-LIMIT': '',
2879
+ }
2880
+ auth = timestamp + method + request
2881
+ if method == 'GET':
2882
+ if query:
2883
+ urlencodedQuery = '?' + self.urlencode(query)
2884
+ url += urlencodedQuery
2885
+ auth += urlencodedQuery
2886
+ else:
2887
+ if isArray or query:
2888
+ body = self.json(query)
2889
+ auth += body
2890
+ headers['Content-Type'] = 'application/json'
2891
+ signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'base64')
2892
+ headers['OK-ACCESS-SIGN'] = signature
2893
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
2894
+
2895
+ def parse_balance_by_type(self, type, response):
2896
+ if type == 'funding':
2897
+ return self.parse_funding_balance(response)
2898
+ else:
2899
+ return self.parse_trading_balance(response)
2900
+
2901
+ def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
2902
+ if not response:
2903
+ return None # fallback to default error handler
2904
+ #
2905
+ # {
2906
+ # "code": "1",
2907
+ # "data": [
2908
+ # {
2909
+ # "clOrdId": "",
2910
+ # "ordId": "",
2911
+ # "sCode": "51119",
2912
+ # "sMsg": "Order placement failed due to insufficient balance. ",
2913
+ # "tag": ""
2914
+ # }
2915
+ # ],
2916
+ # "msg": ""
2917
+ # },
2918
+ # {
2919
+ # "code": "58001",
2920
+ # "data": [],
2921
+ # "msg": "Incorrect trade password"
2922
+ # }
2923
+ #
2924
+ code = self.safe_string(response, 'code')
2925
+ if code != '0':
2926
+ feedback = self.id + ' ' + body
2927
+ data = self.safe_value(response, 'data', [])
2928
+ for i in range(0, len(data)):
2929
+ error = data[i]
2930
+ errorCode = self.safe_string(error, 'sCode')
2931
+ message = self.safe_string(error, 'sMsg')
2932
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
2933
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
2934
+ self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
2935
+ raise ExchangeError(feedback) # unknown message
2936
+ return None