ccxt 4.2.77__py2.py3-none-any.whl → 4.4.49__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 (546) hide show
  1. ccxt/__init__.py +36 -14
  2. ccxt/abstract/alpaca.py +4 -0
  3. ccxt/abstract/bigone.py +1 -1
  4. ccxt/abstract/binance.py +112 -48
  5. ccxt/abstract/binancecoinm.py +112 -48
  6. ccxt/abstract/binanceus.py +147 -83
  7. ccxt/abstract/binanceusdm.py +112 -48
  8. ccxt/abstract/bingx.py +133 -78
  9. ccxt/abstract/bitbank.py +5 -0
  10. ccxt/abstract/bitfinex.py +136 -65
  11. ccxt/abstract/bitfinex1.py +69 -0
  12. ccxt/abstract/bitflyer.py +1 -0
  13. ccxt/abstract/bitget.py +8 -1
  14. ccxt/abstract/bitmart.py +13 -1
  15. ccxt/abstract/bitopro.py +1 -0
  16. ccxt/abstract/bitpanda.py +0 -12
  17. ccxt/abstract/bitrue.py +3 -3
  18. ccxt/abstract/bitstamp.py +26 -3
  19. ccxt/abstract/blofin.py +24 -0
  20. ccxt/abstract/btcbox.py +1 -0
  21. ccxt/abstract/bybit.py +29 -14
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbase.py +6 -0
  24. ccxt/abstract/coinbaseadvanced.py +94 -0
  25. ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
  26. ccxt/abstract/coinbaseinternational.py +1 -1
  27. ccxt/abstract/coincatch.py +94 -0
  28. ccxt/abstract/coinex.py +233 -123
  29. ccxt/abstract/coinmetro.py +1 -0
  30. ccxt/abstract/cryptocom.py +14 -0
  31. ccxt/abstract/defx.py +69 -0
  32. ccxt/abstract/deribit.py +1 -0
  33. ccxt/abstract/digifinex.py +1 -0
  34. ccxt/abstract/ellipx.py +25 -0
  35. ccxt/abstract/gate.py +20 -0
  36. ccxt/abstract/gateio.py +20 -0
  37. ccxt/abstract/gemini.py +1 -0
  38. ccxt/abstract/hashkey.py +67 -0
  39. ccxt/abstract/hyperliquid.py +1 -1
  40. ccxt/abstract/independentreserve.py +6 -0
  41. ccxt/abstract/kraken.py +4 -3
  42. ccxt/abstract/krakenfutures.py +4 -0
  43. ccxt/abstract/kucoin.py +24 -0
  44. ccxt/abstract/kucoinfutures.py +34 -0
  45. ccxt/abstract/luno.py +2 -0
  46. ccxt/abstract/mexc.py +4 -0
  47. ccxt/abstract/myokx.py +340 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +30 -0
  50. ccxt/abstract/onetrading.py +0 -12
  51. ccxt/abstract/oxfun.py +34 -0
  52. ccxt/abstract/paradex.py +40 -0
  53. ccxt/abstract/phemex.py +1 -0
  54. ccxt/abstract/upbit.py +4 -0
  55. ccxt/abstract/vertex.py +19 -0
  56. ccxt/abstract/whitebit.py +31 -1
  57. ccxt/abstract/woo.py +6 -2
  58. ccxt/abstract/woofipro.py +119 -0
  59. ccxt/abstract/xt.py +153 -0
  60. ccxt/abstract/zonda.py +6 -0
  61. ccxt/ace.py +164 -60
  62. ccxt/alpaca.py +727 -63
  63. ccxt/ascendex.py +395 -249
  64. ccxt/async_support/__init__.py +36 -14
  65. ccxt/async_support/ace.py +164 -60
  66. ccxt/async_support/alpaca.py +727 -63
  67. ccxt/async_support/ascendex.py +396 -249
  68. ccxt/async_support/base/exchange.py +531 -155
  69. ccxt/async_support/base/ws/aiohttp_client.py +28 -5
  70. ccxt/async_support/base/ws/cache.py +3 -2
  71. ccxt/async_support/base/ws/client.py +26 -5
  72. ccxt/async_support/base/ws/fast_client.py +4 -3
  73. ccxt/async_support/base/ws/functions.py +1 -1
  74. ccxt/async_support/base/ws/future.py +40 -31
  75. ccxt/async_support/base/ws/order_book_side.py +3 -0
  76. ccxt/async_support/bequant.py +1 -1
  77. ccxt/async_support/bigone.py +329 -202
  78. ccxt/async_support/binance.py +3030 -1087
  79. ccxt/async_support/binancecoinm.py +2 -1
  80. ccxt/async_support/binanceus.py +12 -1
  81. ccxt/async_support/binanceusdm.py +3 -1
  82. ccxt/async_support/bingx.py +3205 -937
  83. ccxt/async_support/bit2c.py +119 -38
  84. ccxt/async_support/bitbank.py +215 -76
  85. ccxt/async_support/bitbns.py +124 -53
  86. ccxt/async_support/bitfinex.py +3236 -1078
  87. ccxt/async_support/bitfinex1.py +1711 -0
  88. ccxt/async_support/bitflyer.py +238 -49
  89. ccxt/async_support/bitget.py +1525 -573
  90. ccxt/async_support/bithumb.py +199 -65
  91. ccxt/async_support/bitmart.py +1320 -435
  92. ccxt/async_support/bitmex.py +308 -111
  93. ccxt/async_support/bitopro.py +256 -96
  94. ccxt/async_support/bitrue.py +365 -233
  95. ccxt/async_support/bitso.py +201 -89
  96. ccxt/async_support/bitstamp.py +438 -269
  97. ccxt/async_support/bitteam.py +179 -73
  98. ccxt/async_support/bitvavo.py +180 -70
  99. ccxt/async_support/bl3p.py +92 -25
  100. ccxt/async_support/blockchaincom.py +193 -79
  101. ccxt/async_support/blofin.py +392 -148
  102. ccxt/async_support/btcalpha.py +161 -55
  103. ccxt/async_support/btcbox.py +250 -34
  104. ccxt/async_support/btcmarkets.py +232 -85
  105. ccxt/async_support/btcturk.py +159 -60
  106. ccxt/async_support/bybit.py +2231 -1193
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1454 -287
  109. ccxt/async_support/coinbaseadvanced.py +17 -0
  110. ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
  111. ccxt/async_support/coinbaseinternational.py +428 -88
  112. ccxt/async_support/coincatch.py +5152 -0
  113. ccxt/async_support/coincheck.py +121 -38
  114. ccxt/async_support/coinex.py +4020 -3339
  115. ccxt/async_support/coinlist.py +273 -116
  116. ccxt/async_support/coinmate.py +204 -97
  117. ccxt/async_support/coinmetro.py +203 -110
  118. ccxt/async_support/coinone.py +142 -68
  119. ccxt/async_support/coinsph.py +223 -97
  120. ccxt/async_support/coinspot.py +137 -62
  121. ccxt/async_support/cryptocom.py +515 -185
  122. ccxt/async_support/currencycom.py +203 -85
  123. ccxt/async_support/defx.py +2066 -0
  124. ccxt/async_support/delta.py +404 -109
  125. ccxt/async_support/deribit.py +639 -323
  126. ccxt/async_support/digifinex.py +465 -233
  127. ccxt/async_support/ellipx.py +1887 -0
  128. ccxt/async_support/exmo.py +317 -128
  129. ccxt/async_support/gate.py +1472 -463
  130. ccxt/async_support/gemini.py +206 -84
  131. ccxt/async_support/hashkey.py +4164 -0
  132. ccxt/async_support/hitbtc.py +433 -178
  133. ccxt/async_support/hollaex.py +207 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +178 -56
  136. ccxt/async_support/hyperliquid.py +1678 -292
  137. ccxt/async_support/idex.py +219 -95
  138. ccxt/async_support/independentreserve.py +300 -31
  139. ccxt/async_support/indodax.py +226 -62
  140. ccxt/async_support/kraken.py +871 -354
  141. ccxt/async_support/krakenfutures.py +324 -100
  142. ccxt/async_support/kucoin.py +917 -357
  143. ccxt/async_support/kucoinfutures.py +1004 -149
  144. ccxt/async_support/kuna.py +198 -107
  145. ccxt/async_support/latoken.py +199 -79
  146. ccxt/async_support/lbank.py +360 -113
  147. ccxt/async_support/luno.py +185 -62
  148. ccxt/async_support/lykke.py +168 -55
  149. ccxt/async_support/mercado.py +101 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +53 -0
  152. ccxt/async_support/ndax.py +234 -82
  153. ccxt/async_support/novadax.py +195 -75
  154. ccxt/async_support/oceanex.py +244 -59
  155. ccxt/async_support/okcoin.py +301 -165
  156. ccxt/async_support/okx.py +1776 -454
  157. ccxt/async_support/onetrading.py +198 -414
  158. ccxt/async_support/oxfun.py +2898 -0
  159. ccxt/async_support/p2b.py +142 -52
  160. ccxt/async_support/paradex.py +2085 -0
  161. ccxt/async_support/paymium.py +56 -32
  162. ccxt/async_support/phemex.py +572 -196
  163. ccxt/async_support/poloniex.py +218 -95
  164. ccxt/async_support/poloniexfutures.py +260 -92
  165. ccxt/async_support/probit.py +143 -110
  166. ccxt/async_support/timex.py +123 -70
  167. ccxt/async_support/tokocrypto.py +129 -93
  168. ccxt/async_support/tradeogre.py +39 -25
  169. ccxt/async_support/upbit.py +322 -113
  170. ccxt/async_support/vertex.py +2983 -0
  171. ccxt/async_support/wavesexchange.py +227 -173
  172. ccxt/async_support/wazirx.py +145 -65
  173. ccxt/async_support/whitebit.py +533 -138
  174. ccxt/async_support/woo.py +1137 -296
  175. ccxt/async_support/woofipro.py +2716 -0
  176. ccxt/async_support/xt.py +4628 -0
  177. ccxt/async_support/yobit.py +160 -92
  178. ccxt/async_support/zaif.py +80 -33
  179. ccxt/async_support/zonda.py +140 -69
  180. ccxt/base/errors.py +51 -20
  181. ccxt/base/exchange.py +1722 -480
  182. ccxt/base/precise.py +10 -0
  183. ccxt/base/types.py +223 -4
  184. ccxt/bequant.py +1 -1
  185. ccxt/bigone.py +329 -202
  186. ccxt/binance.py +3030 -1087
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3205 -937
  191. ccxt/bit2c.py +119 -38
  192. ccxt/bitbank.py +215 -76
  193. ccxt/bitbns.py +124 -53
  194. ccxt/bitfinex.py +3235 -1078
  195. ccxt/bitfinex1.py +1710 -0
  196. ccxt/bitflyer.py +238 -49
  197. ccxt/bitget.py +1525 -573
  198. ccxt/bithumb.py +198 -65
  199. ccxt/bitmart.py +1320 -435
  200. ccxt/bitmex.py +308 -111
  201. ccxt/bitopro.py +256 -96
  202. ccxt/bitrue.py +365 -233
  203. ccxt/bitso.py +201 -89
  204. ccxt/bitstamp.py +438 -269
  205. ccxt/bitteam.py +179 -73
  206. ccxt/bitvavo.py +180 -70
  207. ccxt/bl3p.py +92 -25
  208. ccxt/blockchaincom.py +193 -79
  209. ccxt/blofin.py +392 -148
  210. ccxt/btcalpha.py +161 -55
  211. ccxt/btcbox.py +250 -34
  212. ccxt/btcmarkets.py +232 -85
  213. ccxt/btcturk.py +159 -60
  214. ccxt/bybit.py +2231 -1193
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1454 -287
  217. ccxt/coinbaseadvanced.py +17 -0
  218. ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
  219. ccxt/coinbaseinternational.py +428 -88
  220. ccxt/coincatch.py +5152 -0
  221. ccxt/coincheck.py +121 -38
  222. ccxt/coinex.py +4020 -3339
  223. ccxt/coinlist.py +273 -116
  224. ccxt/coinmate.py +204 -97
  225. ccxt/coinmetro.py +203 -110
  226. ccxt/coinone.py +142 -68
  227. ccxt/coinsph.py +223 -97
  228. ccxt/coinspot.py +137 -62
  229. ccxt/cryptocom.py +515 -185
  230. ccxt/currencycom.py +203 -85
  231. ccxt/defx.py +2065 -0
  232. ccxt/delta.py +404 -109
  233. ccxt/deribit.py +639 -323
  234. ccxt/digifinex.py +465 -233
  235. ccxt/ellipx.py +1887 -0
  236. ccxt/exmo.py +317 -128
  237. ccxt/gate.py +1472 -463
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +433 -178
  241. ccxt/hollaex.py +207 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +178 -56
  244. ccxt/hyperliquid.py +1677 -292
  245. ccxt/idex.py +219 -95
  246. ccxt/independentreserve.py +299 -31
  247. ccxt/indodax.py +226 -62
  248. ccxt/kraken.py +871 -354
  249. ccxt/krakenfutures.py +324 -100
  250. ccxt/kucoin.py +917 -357
  251. ccxt/kucoinfutures.py +1004 -149
  252. ccxt/kuna.py +198 -107
  253. ccxt/latoken.py +199 -79
  254. ccxt/lbank.py +360 -113
  255. ccxt/luno.py +185 -62
  256. ccxt/lykke.py +168 -55
  257. ccxt/mercado.py +101 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +53 -0
  260. ccxt/ndax.py +234 -82
  261. ccxt/novadax.py +195 -75
  262. ccxt/oceanex.py +244 -59
  263. ccxt/okcoin.py +301 -165
  264. ccxt/okx.py +1776 -454
  265. ccxt/onetrading.py +198 -414
  266. ccxt/oxfun.py +2897 -0
  267. ccxt/p2b.py +142 -52
  268. ccxt/paradex.py +2085 -0
  269. ccxt/paymium.py +56 -32
  270. ccxt/phemex.py +572 -196
  271. ccxt/poloniex.py +218 -95
  272. ccxt/poloniexfutures.py +260 -92
  273. ccxt/pro/__init__.py +29 -5
  274. ccxt/pro/alpaca.py +32 -17
  275. ccxt/pro/ascendex.py +62 -14
  276. ccxt/pro/bequant.py +4 -0
  277. ccxt/pro/binance.py +1596 -329
  278. ccxt/pro/binancecoinm.py +1 -0
  279. ccxt/pro/binanceus.py +2 -9
  280. ccxt/pro/binanceusdm.py +2 -0
  281. ccxt/pro/bingx.py +527 -134
  282. ccxt/pro/bitcoincom.py +4 -1
  283. ccxt/pro/bitfinex.py +731 -266
  284. ccxt/pro/bitfinex1.py +635 -0
  285. ccxt/pro/bitget.py +726 -357
  286. ccxt/pro/bithumb.py +380 -0
  287. ccxt/pro/bitmart.py +143 -39
  288. ccxt/pro/bitmex.py +199 -40
  289. ccxt/pro/bitopro.py +25 -13
  290. ccxt/pro/bitrue.py +31 -32
  291. ccxt/pro/bitstamp.py +7 -6
  292. ccxt/pro/bitvavo.py +203 -81
  293. ccxt/pro/blockchaincom.py +30 -17
  294. ccxt/pro/blofin.py +692 -0
  295. ccxt/pro/bybit.py +791 -82
  296. ccxt/pro/cex.py +99 -51
  297. ccxt/pro/coinbase.py +220 -30
  298. ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
  299. ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
  300. ccxt/pro/coinbaseinternational.py +193 -30
  301. ccxt/pro/coincatch.py +1464 -0
  302. ccxt/pro/coincheck.py +11 -6
  303. ccxt/pro/coinex.py +965 -665
  304. ccxt/pro/coinone.py +17 -10
  305. ccxt/pro/cryptocom.py +446 -66
  306. ccxt/pro/currencycom.py +11 -10
  307. ccxt/pro/defx.py +832 -0
  308. ccxt/pro/deribit.py +167 -31
  309. ccxt/pro/exmo.py +252 -20
  310. ccxt/pro/gate.py +729 -64
  311. ccxt/pro/gemini.py +44 -26
  312. ccxt/pro/hashkey.py +802 -0
  313. ccxt/pro/hitbtc.py +208 -103
  314. ccxt/pro/hollaex.py +25 -9
  315. ccxt/pro/htx.py +83 -39
  316. ccxt/pro/huobijp.py +17 -16
  317. ccxt/pro/hyperliquid.py +502 -31
  318. ccxt/pro/idex.py +28 -13
  319. ccxt/pro/independentreserve.py +21 -16
  320. ccxt/pro/kraken.py +298 -51
  321. ccxt/pro/krakenfutures.py +166 -75
  322. ccxt/pro/kucoin.py +395 -77
  323. ccxt/pro/kucoinfutures.py +400 -99
  324. ccxt/pro/lbank.py +52 -31
  325. ccxt/pro/luno.py +12 -10
  326. ccxt/pro/mexc.py +400 -50
  327. ccxt/pro/myokx.py +28 -0
  328. ccxt/pro/ndax.py +25 -12
  329. ccxt/pro/okcoin.py +28 -9
  330. ccxt/pro/okx.py +935 -124
  331. ccxt/pro/onetrading.py +41 -24
  332. ccxt/pro/oxfun.py +1054 -0
  333. ccxt/pro/p2b.py +100 -24
  334. ccxt/pro/paradex.py +352 -0
  335. ccxt/pro/phemex.py +92 -33
  336. ccxt/pro/poloniex.py +128 -49
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +92 -85
  339. ccxt/pro/upbit.py +401 -8
  340. ccxt/pro/vertex.py +943 -0
  341. ccxt/pro/wazirx.py +46 -28
  342. ccxt/pro/whitebit.py +65 -12
  343. ccxt/pro/woo.py +437 -65
  344. ccxt/pro/woofipro.py +1271 -0
  345. ccxt/pro/xt.py +1067 -0
  346. ccxt/probit.py +143 -110
  347. ccxt/static_dependencies/__init__.py +1 -1
  348. ccxt/static_dependencies/lark/__init__.py +38 -0
  349. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  350. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  351. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  352. ccxt/static_dependencies/lark/common.py +86 -0
  353. ccxt/static_dependencies/lark/exceptions.py +292 -0
  354. ccxt/static_dependencies/lark/grammar.py +130 -0
  355. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  356. ccxt/static_dependencies/lark/indenter.py +143 -0
  357. ccxt/static_dependencies/lark/lark.py +658 -0
  358. ccxt/static_dependencies/lark/lexer.py +678 -0
  359. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  360. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  361. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  362. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  363. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  364. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  365. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  366. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  367. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  368. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  369. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  370. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  371. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  372. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  373. ccxt/static_dependencies/lark/py.typed +0 -0
  374. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  375. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  376. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  377. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  378. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  379. ccxt/static_dependencies/lark/tree.py +267 -0
  380. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  381. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  382. ccxt/static_dependencies/lark/utils.py +343 -0
  383. ccxt/static_dependencies/lark/visitors.py +596 -0
  384. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  385. ccxt/static_dependencies/marshmallow/base.py +65 -0
  386. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  387. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  388. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  389. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  390. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  391. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  392. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  393. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  394. ccxt/static_dependencies/marshmallow/types.py +12 -0
  395. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  396. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  397. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  398. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  399. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  400. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  401. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  402. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  403. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  404. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  405. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  406. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  407. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  408. ccxt/static_dependencies/starknet/__init__.py +0 -0
  409. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  410. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  411. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  412. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  413. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  414. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  415. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  416. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  417. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  418. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  419. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  420. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  421. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  422. ccxt/static_dependencies/starknet/common.py +15 -0
  423. ccxt/static_dependencies/starknet/constants.py +39 -0
  424. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  425. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  426. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  427. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  428. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  429. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  430. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  431. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  432. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  433. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  434. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  435. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  436. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  437. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  438. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  439. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  440. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  441. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  442. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  443. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  444. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  445. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  446. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  447. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  448. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  449. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  450. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  451. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  452. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  453. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  454. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  455. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  456. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  457. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  458. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  459. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  460. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  461. ccxt/static_dependencies/starkware/__init__.py +0 -0
  462. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  463. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  464. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  465. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  466. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  467. ccxt/static_dependencies/sympy/__init__.py +0 -0
  468. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  469. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  470. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  471. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  472. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  473. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  474. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  475. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  476. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  477. ccxt/test/{test_async.py → tests_async.py} +456 -391
  478. ccxt/test/tests_helpers.py +285 -0
  479. ccxt/test/tests_init.py +39 -0
  480. ccxt/test/{test_sync.py → tests_sync.py} +456 -393
  481. ccxt/timex.py +123 -70
  482. ccxt/tokocrypto.py +129 -93
  483. ccxt/tradeogre.py +39 -25
  484. ccxt/upbit.py +322 -113
  485. ccxt/vertex.py +2983 -0
  486. ccxt/wavesexchange.py +227 -173
  487. ccxt/wazirx.py +145 -65
  488. ccxt/whitebit.py +533 -138
  489. ccxt/woo.py +1137 -296
  490. ccxt/woofipro.py +2716 -0
  491. ccxt/xt.py +4627 -0
  492. ccxt/yobit.py +159 -92
  493. ccxt/zaif.py +80 -33
  494. ccxt/zonda.py +140 -69
  495. ccxt-4.4.49.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.49.dist-info/METADATA +646 -0
  497. ccxt-4.4.49.dist-info/RECORD +669 -0
  498. {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/WHEEL +1 -1
  499. ccxt/abstract/bitbay.py +0 -47
  500. ccxt/abstract/bitfinex2.py +0 -139
  501. ccxt/abstract/hitbtc3.py +0 -115
  502. ccxt/async_support/bitbay.py +0 -17
  503. ccxt/async_support/bitfinex2.py +0 -3496
  504. ccxt/async_support/flowbtc.py +0 -34
  505. ccxt/bitbay.py +0 -17
  506. ccxt/bitfinex2.py +0 -3496
  507. ccxt/flowbtc.py +0 -34
  508. ccxt/hitbtc3.py +0 -16
  509. ccxt/pro/bitfinex2.py +0 -1081
  510. ccxt/test/base/__init__.py +0 -28
  511. ccxt/test/base/test_account.py +0 -26
  512. ccxt/test/base/test_balance.py +0 -56
  513. ccxt/test/base/test_borrow_interest.py +0 -35
  514. ccxt/test/base/test_borrow_rate.py +0 -32
  515. ccxt/test/base/test_calculate_fee.py +0 -51
  516. ccxt/test/base/test_crypto.py +0 -127
  517. ccxt/test/base/test_currency.py +0 -76
  518. ccxt/test/base/test_datetime.py +0 -103
  519. ccxt/test/base/test_decimal_to_precision.py +0 -392
  520. ccxt/test/base/test_deep_extend.py +0 -68
  521. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  522. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  523. ccxt/test/base/test_funding_rate_history.py +0 -29
  524. ccxt/test/base/test_last_price.py +0 -32
  525. ccxt/test/base/test_ledger_entry.py +0 -45
  526. ccxt/test/base/test_ledger_item.py +0 -48
  527. ccxt/test/base/test_leverage_tier.py +0 -33
  528. ccxt/test/base/test_margin_mode.py +0 -24
  529. ccxt/test/base/test_margin_modification.py +0 -35
  530. ccxt/test/base/test_market.py +0 -190
  531. ccxt/test/base/test_number.py +0 -411
  532. ccxt/test/base/test_ohlcv.py +0 -32
  533. ccxt/test/base/test_open_interest.py +0 -32
  534. ccxt/test/base/test_order.py +0 -64
  535. ccxt/test/base/test_order_book.py +0 -63
  536. ccxt/test/base/test_position.py +0 -60
  537. ccxt/test/base/test_shared_methods.py +0 -345
  538. ccxt/test/base/test_status.py +0 -24
  539. ccxt/test/base/test_throttle.py +0 -126
  540. ccxt/test/base/test_ticker.py +0 -86
  541. ccxt/test/base/test_trade.py +0 -47
  542. ccxt/test/base/test_trading_fee.py +0 -26
  543. ccxt/test/base/test_transaction.py +0 -39
  544. ccxt-4.2.77.dist-info/METADATA +0 -626
  545. ccxt-4.2.77.dist-info/RECORD +0 -534
  546. {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/top_level.txt +0 -0
ccxt/okx.py CHANGED
@@ -6,29 +6,33 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.okx import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Account, Balances, Currency, Greeks, Int, Leverage, Market, MarketInterface, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
9
+ from ccxt.base.types import Account, Balances, BorrowInterest, Conversion, CrossBorrowRate, CrossBorrowRates, Currencies, Currency, DepositAddress, Greeks, Int, LedgerEntry, Leverage, LeverageTier, LongShortRatio, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, Trade, TradingFeeInterface, Transaction, TransferEntry
10
10
  from typing import List
11
+ from typing import Any
11
12
  from ccxt.base.errors import ExchangeError
13
+ from ccxt.base.errors import AuthenticationError
12
14
  from ccxt.base.errors import PermissionDenied
13
15
  from ccxt.base.errors import AccountNotEnabled
14
16
  from ccxt.base.errors import AccountSuspended
15
17
  from ccxt.base.errors import ArgumentsRequired
16
18
  from ccxt.base.errors import BadRequest
17
19
  from ccxt.base.errors import BadSymbol
20
+ from ccxt.base.errors import OperationRejected
21
+ from ccxt.base.errors import ManualInteractionNeeded
18
22
  from ccxt.base.errors import InsufficientFunds
19
23
  from ccxt.base.errors import InvalidAddress
20
24
  from ccxt.base.errors import InvalidOrder
21
25
  from ccxt.base.errors import OrderNotFound
22
- from ccxt.base.errors import CancelPending
26
+ from ccxt.base.errors import ContractUnavailable
23
27
  from ccxt.base.errors import NotSupported
24
28
  from ccxt.base.errors import NetworkError
29
+ from ccxt.base.errors import DDoSProtection
25
30
  from ccxt.base.errors import RateLimitExceeded
26
31
  from ccxt.base.errors import ExchangeNotAvailable
27
32
  from ccxt.base.errors import OnMaintenance
28
33
  from ccxt.base.errors import InvalidNonce
29
34
  from ccxt.base.errors import RequestTimeout
30
- from ccxt.base.errors import AuthenticationError
31
- from ccxt.base.errors import ContractUnavailable
35
+ from ccxt.base.errors import CancelPending
32
36
  from ccxt.base.decimal_to_precision import TICK_SIZE
33
37
  from ccxt.base.precise import Precise
34
38
 
@@ -53,10 +57,13 @@ class okx(Exchange, ImplicitAPI):
53
57
  'option': True,
54
58
  'addMargin': True,
55
59
  'cancelAllOrders': False,
60
+ 'cancelAllOrdersAfter': True,
56
61
  'cancelOrder': True,
57
62
  'cancelOrders': True,
63
+ 'cancelOrdersForSymbols': True,
58
64
  'closeAllPositions': False,
59
65
  'closePosition': True,
66
+ 'createConvertTrade': True,
60
67
  'createDepositAddress': False,
61
68
  'createMarketBuyOrderWithCost': True,
62
69
  'createMarketSellOrderWithCost': True,
@@ -82,6 +89,10 @@ class okx(Exchange, ImplicitAPI):
82
89
  'fetchCanceledOrders': True,
83
90
  'fetchClosedOrder': None,
84
91
  'fetchClosedOrders': True,
92
+ 'fetchConvertCurrencies': True,
93
+ 'fetchConvertQuote': True,
94
+ 'fetchConvertTrade': True,
95
+ 'fetchConvertTradeHistory': True,
85
96
  'fetchCrossBorrowRate': True,
86
97
  'fetchCrossBorrowRates': True,
87
98
  'fetchCurrencies': True,
@@ -94,6 +105,8 @@ class okx(Exchange, ImplicitAPI):
94
105
  'fetchDepositWithdrawFee': 'emulated',
95
106
  'fetchDepositWithdrawFees': True,
96
107
  'fetchFundingHistory': True,
108
+ 'fetchFundingInterval': True,
109
+ 'fetchFundingIntervals': False,
97
110
  'fetchFundingRate': True,
98
111
  'fetchFundingRateHistory': True,
99
112
  'fetchFundingRates': False,
@@ -106,9 +119,14 @@ class okx(Exchange, ImplicitAPI):
106
119
  'fetchLedgerEntry': None,
107
120
  'fetchLeverage': True,
108
121
  'fetchLeverageTiers': False,
122
+ 'fetchLongShortRatio': False,
123
+ 'fetchLongShortRatioHistory': True,
124
+ 'fetchMarginAdjustmentHistory': True,
109
125
  'fetchMarketLeverageTiers': True,
110
126
  'fetchMarkets': True,
111
127
  'fetchMarkOHLCV': True,
128
+ 'fetchMarkPrice': True,
129
+ 'fetchMarkPrices': True,
112
130
  'fetchMySettlementHistory': False,
113
131
  'fetchMyTrades': True,
114
132
  'fetchOHLCV': True,
@@ -116,15 +134,18 @@ class okx(Exchange, ImplicitAPI):
116
134
  'fetchOpenInterestHistory': True,
117
135
  'fetchOpenOrder': None,
118
136
  'fetchOpenOrders': True,
137
+ 'fetchOption': True,
138
+ 'fetchOptionChain': True,
119
139
  'fetchOrder': True,
120
140
  'fetchOrderBook': True,
121
141
  'fetchOrderBooks': False,
122
142
  'fetchOrders': False,
123
143
  'fetchOrderTrades': True,
124
- 'fetchPermissions': None,
125
144
  'fetchPosition': True,
145
+ 'fetchPositionHistory': 'emulated',
126
146
  'fetchPositions': True,
127
147
  'fetchPositionsForSymbol': True,
148
+ 'fetchPositionsHistory': True,
128
149
  'fetchPositionsRisk': False,
129
150
  'fetchPremiumIndexOHLCV': False,
130
151
  'fetchSettlementHistory': True,
@@ -148,6 +169,7 @@ class okx(Exchange, ImplicitAPI):
148
169
  'fetchWithdrawalWhitelist': False,
149
170
  'reduceMargin': True,
150
171
  'repayCrossMargin': True,
172
+ 'sandbox': True,
151
173
  'setLeverage': True,
152
174
  'setMargin': False,
153
175
  'setMarginMode': True,
@@ -241,6 +263,7 @@ class okx(Exchange, ImplicitAPI):
241
263
  'rubik/stat/margin/loan-ratio': 4,
242
264
  # long/short
243
265
  'rubik/stat/contracts/long-short-account-ratio': 4,
266
+ 'rubik/stat/contracts/long-short-account-ratio-contract': 4,
244
267
  'rubik/stat/contracts/open-interest-volume': 4,
245
268
  'rubik/stat/option/open-interest-volume': 4,
246
269
  # put/call
@@ -254,13 +277,20 @@ class okx(Exchange, ImplicitAPI):
254
277
  'sprd/books': 1 / 2,
255
278
  'sprd/ticker': 1,
256
279
  'sprd/public-trades': 1 / 5,
280
+ 'market/sprd-ticker': 2,
281
+ 'market/sprd-candles': 2,
282
+ 'market/sprd-history-candles': 2,
257
283
  'tradingBot/grid/ai-param': 1,
258
284
  'tradingBot/grid/min-investment': 1,
259
285
  'tradingBot/public/rsi-back-testing': 1,
260
286
  'asset/exchange-list': 5 / 3,
261
287
  'finance/staking-defi/eth/apy-history': 5 / 3,
288
+ 'finance/staking-defi/sol/apy-history': 5 / 3,
262
289
  'finance/savings/lending-rate-summary': 5 / 3,
263
290
  'finance/savings/lending-rate-history': 5 / 3,
291
+ 'finance/fixed-loan/lending-offers': 10 / 3,
292
+ 'finance/fixed-loan/lending-apy-history': 10 / 3,
293
+ 'finance/fixed-loan/pending-lending-volume': 10 / 3,
264
294
  # public broker
265
295
  'finance/sfp/dcd/products': 2 / 3,
266
296
  # copytrading
@@ -270,6 +300,7 @@ class okx(Exchange, ImplicitAPI):
270
300
  'copytrading/public-preference-currency': 4,
271
301
  'copytrading/public-current-subpositions': 4,
272
302
  'copytrading/public-subpositions-history': 4,
303
+ 'support/announcements-types': 20,
273
304
  },
274
305
  },
275
306
  'private': {
@@ -321,12 +352,14 @@ class okx(Exchange, ImplicitAPI):
321
352
  'asset/convert/history': 5 / 3,
322
353
  'asset/monthly-statement': 2,
323
354
  # account
355
+ 'account/instruments': 1,
324
356
  'account/balance': 2,
325
357
  'account/positions': 2,
326
358
  'account/positions-history': 100,
327
359
  'account/account-position-risk': 2,
328
360
  'account/bills': 5 / 3,
329
361
  'account/bills-archive': 5 / 3,
362
+ 'account/bills-history-archive': 2,
330
363
  'account/config': 4,
331
364
  'account/max-size': 1,
332
365
  'account/max-avail-size': 1,
@@ -348,6 +381,12 @@ class okx(Exchange, ImplicitAPI):
348
381
  'account/greeks': 2,
349
382
  'account/position-tiers': 2,
350
383
  'account/mmp-config': 4,
384
+ 'account/fixed-loan/borrowing-limit': 4,
385
+ 'account/fixed-loan/borrowing-quote': 5,
386
+ 'account/fixed-loan/borrowing-orders-list': 5,
387
+ 'account/spot-manual-borrow-repay': 10,
388
+ 'account/set-auto-repay': 4,
389
+ 'account/spot-borrow-repay-history': 4,
351
390
  # subaccount
352
391
  'users/subaccount/list': 10,
353
392
  'account/subaccount/balances': 10 / 3,
@@ -384,6 +423,9 @@ class okx(Exchange, ImplicitAPI):
384
423
  # eth staking
385
424
  'finance/staking-defi/eth/balance': 5 / 3,
386
425
  'finance/staking-defi/eth/purchase-redeem-history': 5 / 3,
426
+ 'finance/staking-defi/eth/product-info': 3,
427
+ 'finance/staking-defi/sol/balance': 5 / 3,
428
+ 'finance/staking-defi/sol/purchase-redeem-history': 5 / 3,
387
429
  # copytrading
388
430
  'copytrading/current-subpositions': 1,
389
431
  'copytrading/subpositions-history': 1,
@@ -411,6 +453,7 @@ class okx(Exchange, ImplicitAPI):
411
453
  # affiliate
412
454
  'affiliate/invitee/detail': 1,
413
455
  'users/partner/if-rebate': 1,
456
+ 'support/announcements': 4,
414
457
  },
415
458
  'post': {
416
459
  # rfq
@@ -431,6 +474,7 @@ class okx(Exchange, ImplicitAPI):
431
474
  'sprd/cancel-order': 1,
432
475
  'sprd/mass-cancel': 1,
433
476
  'sprd/amend-order': 1,
477
+ 'sprd/cancel-all-after': 10,
434
478
  # trade
435
479
  'trade/order': 1 / 3,
436
480
  'trade/batch-orders': 1 / 15,
@@ -473,6 +517,11 @@ class okx(Exchange, ImplicitAPI):
473
517
  'account/set-account-level': 4,
474
518
  'account/mmp-reset': 4,
475
519
  'account/mmp-config': 100,
520
+ 'account/fixed-loan/borrowing-order': 5,
521
+ 'account/fixed-loan/amend-borrowing-order': 5,
522
+ 'account/fixed-loan/manual-reborrow': 5,
523
+ 'account/fixed-loan/repay-borrowing-order': 5,
524
+ 'account/bills-history-archive': 72000, # 12 req/day
476
525
  # subaccount
477
526
  'users/subaccount/modify-apikey': 10,
478
527
  'asset/subaccount/transfer': 10,
@@ -489,6 +538,7 @@ class okx(Exchange, ImplicitAPI):
489
538
  'tradingBot/grid/compute-margin-balance': 1,
490
539
  'tradingBot/grid/margin-balance': 1,
491
540
  'tradingBot/grid/min-investment': 1,
541
+ 'tradingBot/grid/adjust-investment': 1,
492
542
  'tradingBot/signal/create-signal': 1,
493
543
  'tradingBot/signal/order-algo': 1,
494
544
  'tradingBot/signal/stop-order-algo': 1,
@@ -510,6 +560,8 @@ class okx(Exchange, ImplicitAPI):
510
560
  # eth staking
511
561
  'finance/staking-defi/eth/purchase': 5,
512
562
  'finance/staking-defi/eth/redeem': 5,
563
+ 'finance/staking-defi/sol/purchase': 5,
564
+ 'finance/staking-defi/sol/redeem': 5,
513
565
  # copytrading
514
566
  'copytrading/algo-order': 1,
515
567
  'copytrading/close-subposition': 1,
@@ -566,6 +618,7 @@ class okx(Exchange, ImplicitAPI):
566
618
  # General Class
567
619
  '1': ExchangeError, # Operation failed
568
620
  '2': ExchangeError, # Bulk operation partially succeeded
621
+ '4088': ManualInteractionNeeded, # {"code":"4088","data":[],"msg":"You can’t trade or deposit until you’ve verified your identity again. Head to Identity Verification to complete it."}
569
622
  '50000': BadRequest, # Body can not be empty
570
623
  '50001': OnMaintenance, # Matching engine upgrading. Please try again later
571
624
  '50002': BadRequest, # Json data format error
@@ -595,6 +648,7 @@ class okx(Exchange, ImplicitAPI):
595
648
  '50027': PermissionDenied, # The account is restricted from trading
596
649
  '50028': ExchangeError, # Unable to take the order, please reach out to support center for details
597
650
  '50044': BadRequest, # Must select one broker type
651
+ '50061': ExchangeError, # You've reached the maximum order rate limit for self account.
598
652
  '50062': ExchangeError, # This feature is currently unavailable.
599
653
  # API Class
600
654
  '50100': ExchangeError, # API frozen, please contact customer service
@@ -782,6 +836,18 @@ class okx(Exchange, ImplicitAPI):
782
836
  # SPOT/MARGIN error codes 54000-54999
783
837
  '54000': ExchangeError, # Margin transactions unavailable
784
838
  '54001': ExchangeError, # Only Multi-currency margin account can be set to borrow coins automatically
839
+ '54008': InvalidOrder, # This operation is disabled by the 'mass cancel order' endpoint. Please enable it using self endpoint.
840
+ '54009': InvalidOrder, # The range of {param0} should be [{param1}, {param2}].
841
+ '54011': InvalidOrder, # 200 Pre-market trading contracts are only allowed to reduce the number of positions within 1 hour before delivery. Please modify or cancel the order.
842
+ # Trading bot Error Code from 55100 to 55999
843
+ '55100': InvalidOrder, # Take profit % should be within the range of {parameter1}-{parameter2}
844
+ '55101': InvalidOrder, # Stop loss % should be within the range of {parameter1}-{parameter2}
845
+ '55102': InvalidOrder, # Take profit % should be greater than the current bot’s PnL%
846
+ '55103': InvalidOrder, # Stop loss % should be less than the current bot’s PnL%
847
+ '55104': InvalidOrder, # Only futures grid supports take profit or stop loss based on profit percentage
848
+ '55111': InvalidOrder, # This signal name is in use, please try a new name
849
+ '55112': InvalidOrder, # This signal does not exist
850
+ '55113': InvalidOrder, # Create signal strategies with leverage greater than the maximum leverage of the instruments
785
851
  # FUNDING error codes 58000-58999
786
852
  '58000': ExchangeError, # Account type {0} does not supported when getting the sub-account balance
787
853
  '58001': AuthenticationError, # Incorrect trade password
@@ -857,6 +923,11 @@ class okx(Exchange, ImplicitAPI):
857
923
  '59301': ExchangeError, # Margin adjustment failed for exceeding the max limit
858
924
  '59313': ExchangeError, # Unable to repay. You haven't borrowed any {ccy} {ccyPair} in Quick margin mode.
859
925
  '59401': ExchangeError, # Holdings already reached the limit
926
+ '59410': OperationRejected, # You can only borrow self crypto if it supports borrowing and borrowing is enabled.
927
+ '59411': InsufficientFunds, # Manual borrowing failed. Your account's free margin is insufficient
928
+ '59412': OperationRejected, # Manual borrowing failed. The amount exceeds your borrowing limit.
929
+ '59413': OperationRejected, # You didn't borrow self crypto. No repayment needed.
930
+ '59414': BadRequest, # Manual borrowing failed. The minimum borrowing limit is {param0}.needed.
860
931
  '59500': ExchangeError, # Only the APIKey of the main account has permission
861
932
  '59501': ExchangeError, # Only 50 APIKeys can be created per account
862
933
  '59502': ExchangeError, # Note name cannot be duplicate with the currently created APIKey note name
@@ -888,10 +959,36 @@ class okx(Exchange, ImplicitAPI):
888
959
  '60017': BadRequest, # Invalid url path
889
960
  '60018': BadRequest, # The {0} {1} {2} {3} {4} does not exist
890
961
  '60019': BadRequest, # Invalid op {op}
962
+ '60020': ExchangeError, # APIKey subscription amount exceeds the limit
963
+ '60021': AccountNotEnabled, # This operation does not support multiple accounts login
964
+ '60022': AuthenticationError, # Bulk login partially succeeded
965
+ '60023': DDoSProtection, # Bulk login requests too frequent
966
+ '60024': AuthenticationError, # Wrong passphrase
967
+ '60025': ExchangeError, # Token subscription amount exceeds the limit
968
+ '60026': AuthenticationError, # Batch login by APIKey and token simultaneously is not supported
969
+ '60027': ArgumentsRequired, # Parameter {0} can not be empty
970
+ '60028': NotSupported, # The current operation is not supported by self URL
971
+ '60029': AccountNotEnabled, # Only users who are VIP5 and above in trading fee tier are allowed to subscribe to books-l2-tbt channel
972
+ '60030': AccountNotEnabled, # Only users who are VIP4 and above in trading fee tier are allowed to subscribe to books50-l2-tbt channel
973
+ '60031': AuthenticationError, # The WebSocket endpoint does not support multiple account batch login,
974
+ '60032': AuthenticationError, # API key doesn't exist,
891
975
  '63999': ExchangeError, # Internal system error
976
+ '64000': BadRequest, # Subscription parameter uly is unavailable anymore, please replace uly with instFamily. More details can refer to: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url,
977
+ '64001': BadRequest, # This channel has been migrated to the business URL. Please subscribe using the new URL. More details can refer to: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url,
978
+ '64002': BadRequest, # This channel is not supported by business URL. Please use "/private" URL(for private channels), or "/public" URL(for public channels). More details can refer to: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url,
979
+ '64003': AccountNotEnabled, # Your trading fee tier doesnt meet the requirement to access self channel
892
980
  '70010': BadRequest, # Timestamp parameters need to be in Unix timestamp format in milliseconds.
893
981
  '70013': BadRequest, # endTs needs to be bigger than or equal to beginTs.
894
982
  '70016': BadRequest, # Please specify your instrument settings for at least one instType.
983
+ '1009': BadRequest, # Request message exceeds the maximum frame length
984
+ '4001': AuthenticationError, # Login Failed
985
+ '4002': BadRequest, # Invalid Request
986
+ '4003': RateLimitExceeded, # APIKey subscription amount exceeds the limit 100
987
+ '4004': NetworkError, # No data received in 30s
988
+ '4005': ExchangeNotAvailable, # Buffer is full, cannot write data
989
+ '4006': BadRequest, # Abnormal disconnection
990
+ '4007': AuthenticationError, # API key has been updated or deleted. Please reconnect.
991
+ '4008': RateLimitExceeded, # The number of subscribed channels exceeds the maximum limit.
895
992
  },
896
993
  'broad': {
897
994
  'Internal Server Error': ExchangeNotAvailable, # {"code":500,"data":{},"detailMsg":"","error_code":"500","error_message":"Internal Server Error","msg":"Internal Server Error"}
@@ -923,7 +1020,7 @@ class okx(Exchange, ImplicitAPI):
923
1020
  'BHP': 'BHP',
924
1021
  'APT': 'Aptos',
925
1022
  'ARBONE': 'Arbitrum One',
926
- 'AVAXC': 'Avalanche C',
1023
+ 'AVAXC': 'Avalanche C-Chain',
927
1024
  'AVAXX': 'Avalanche X-Chain',
928
1025
  'ARK': 'ARK',
929
1026
  'AR': 'Arweave',
@@ -996,6 +1093,7 @@ class okx(Exchange, ImplicitAPI):
996
1093
  'ZEC': 'Zcash',
997
1094
  'ZIL': 'Zilliqa',
998
1095
  'ZKSYNC': 'ZKSYNC',
1096
+ 'OMNI': 'Omni',
999
1097
  # 'NEON3': 'N3', # tbd
1000
1098
  # undetermined : "CELO-TOKEN", "Digital Cash", Khala
1001
1099
  # todo: uncomment below after consensus
@@ -1041,6 +1139,8 @@ class okx(Exchange, ImplicitAPI):
1041
1139
  'createOrder': 'privatePostTradeBatchOrders', # or 'privatePostTradeOrder' or 'privatePostTradeOrderAlgo'
1042
1140
  'createMarketBuyOrderRequiresPrice': False,
1043
1141
  'fetchMarkets': ['spot', 'future', 'swap', 'option'], # spot, future, swap, option
1142
+ 'timeDifference': 0, # the difference between system clock and exchange server clock
1143
+ 'adjustForTimeDifference': False, # controls the adjustment logic upon instantiation
1044
1144
  'defaultType': 'spot', # 'funding', 'spot', 'margin', 'future', 'swap', 'option'
1045
1145
  # 'fetchBalance': {
1046
1146
  # 'type': 'spot', # 'funding', 'trading', 'spot'
@@ -1107,6 +1207,96 @@ class okx(Exchange, ImplicitAPI):
1107
1207
  },
1108
1208
  'brokerId': 'e847386590ce4dBC',
1109
1209
  },
1210
+ 'features': {
1211
+ 'default': {
1212
+ 'sandbox': True,
1213
+ 'createOrder': {
1214
+ 'marginMode': True,
1215
+ 'triggerPrice': True,
1216
+ 'triggerPriceType': {
1217
+ 'last': True,
1218
+ 'mark': True,
1219
+ 'index': True,
1220
+ },
1221
+ 'triggerDirection': False,
1222
+ 'stopLossPrice': True,
1223
+ 'takeProfitPrice': True,
1224
+ 'attachedStopLossTakeProfit': {
1225
+ 'triggerPriceType': {
1226
+ 'last': True,
1227
+ 'mark': True,
1228
+ 'index': True,
1229
+ },
1230
+ 'price': True,
1231
+ },
1232
+ 'timeInForce': {
1233
+ 'IOC': True,
1234
+ 'FOK': True,
1235
+ 'PO': True,
1236
+ 'GTD': False,
1237
+ },
1238
+ 'hedged': True,
1239
+ 'trailing': True,
1240
+ 'iceberg': True, # todo implement
1241
+ 'leverage': False,
1242
+ 'selfTradePrevention': True, # todo implement
1243
+ 'marketBuyByCost': True,
1244
+ 'marketBuyRequiresPrice': False,
1245
+ },
1246
+ 'createOrders': {
1247
+ 'max': 20,
1248
+ },
1249
+ 'fetchMyTrades': {
1250
+ 'marginMode': False,
1251
+ 'daysBack': 90,
1252
+ 'limit': 100,
1253
+ 'untilDays': 10000,
1254
+ },
1255
+ 'fetchOrder': {
1256
+ 'marginMode': False,
1257
+ 'trigger': True,
1258
+ 'trailing': True,
1259
+ },
1260
+ 'fetchOpenOrders': {
1261
+ 'marginMode': False,
1262
+ 'limit': 100,
1263
+ 'trigger': True,
1264
+ 'trailing': True,
1265
+ },
1266
+ 'fetchOrders': None, # not supported
1267
+ 'fetchClosedOrders': {
1268
+ 'marginMode': False,
1269
+ 'limit': 100,
1270
+ 'daysBack': 90, # 3 months
1271
+ 'daysBackCanceled': 1 / 12, # 2 hour
1272
+ 'untilDays': None,
1273
+ 'trigger': True,
1274
+ 'trailing': True,
1275
+ },
1276
+ 'fetchOHLCV': {
1277
+ 'limit': 300,
1278
+ },
1279
+ },
1280
+ 'spot': {
1281
+ 'extends': 'default',
1282
+ },
1283
+ 'swap': {
1284
+ 'linear': {
1285
+ 'extends': 'default',
1286
+ },
1287
+ 'inverse': {
1288
+ 'extends': 'default',
1289
+ },
1290
+ },
1291
+ 'future': {
1292
+ 'linear': {
1293
+ 'extends': 'default',
1294
+ },
1295
+ 'inverse': {
1296
+ 'extends': 'default',
1297
+ },
1298
+ },
1299
+ },
1110
1300
  'commonCurrencies': {
1111
1301
  # the exchange refers to ERC20 version of Aeternity(AEToken)
1112
1302
  'AE': 'AET', # https://github.com/ccxt/ccxt/issues/4981
@@ -1114,26 +1304,18 @@ class okx(Exchange, ImplicitAPI):
1114
1304
  },
1115
1305
  })
1116
1306
 
1117
- def handle_market_type_and_params(self, methodName, market=None, params={}):
1307
+ def handle_market_type_and_params(self, methodName: str, market: Market = None, params={}, defaultValue=None) -> Any:
1118
1308
  instType = self.safe_string(params, 'instType')
1119
1309
  params = self.omit(params, 'instType')
1120
1310
  type = self.safe_string(params, 'type')
1121
1311
  if (type is None) and (instType is not None):
1122
1312
  params['type'] = instType
1123
- return super(okx, self).handle_market_type_and_params(methodName, market, params)
1313
+ return super(okx, self).handle_market_type_and_params(methodName, market, params, defaultValue)
1124
1314
 
1125
1315
  def convert_to_instrument_type(self, type):
1126
- exchangeTypes = self.safe_value(self.options, 'exchangeType', {})
1316
+ exchangeTypes = self.safe_dict(self.options, 'exchangeType', {})
1127
1317
  return self.safe_string(exchangeTypes, type, type)
1128
1318
 
1129
- def convert_expire_date(self, date):
1130
- # parse YYMMDD to timestamp
1131
- year = date[0:2]
1132
- month = date[2:4]
1133
- day = date[4:6]
1134
- reconstructedDate = '20' + year + '-' + month + '-' + day + 'T00:00:00Z'
1135
- return reconstructedDate
1136
-
1137
1319
  def create_expired_option_market(self, symbol: str):
1138
1320
  # support expired option contracts
1139
1321
  quote = 'USD'
@@ -1205,7 +1387,9 @@ class okx(Exchange, ImplicitAPI):
1205
1387
  def fetch_status(self, params={}):
1206
1388
  """
1207
1389
  the latest known information on the availability of the exchange API
1208
- :see: https://www.okx.com/docs-v5/en/#status-get-status
1390
+
1391
+ https://www.okx.com/docs-v5/en/#status-get-status
1392
+
1209
1393
  :param dict [params]: extra parameters specific to the exchange API endpoint
1210
1394
  :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
1211
1395
  """
@@ -1230,9 +1414,9 @@ class okx(Exchange, ImplicitAPI):
1230
1414
  # ]
1231
1415
  # }
1232
1416
  #
1233
- data = self.safe_value(response, 'data', [])
1417
+ data = self.safe_list(response, 'data', [])
1234
1418
  dataLength = len(data)
1235
- update = {
1419
+ update: dict = {
1236
1420
  'updated': None,
1237
1421
  'status': 'ok' if (dataLength == 0) else 'maintenance',
1238
1422
  'eta': None,
@@ -1257,7 +1441,9 @@ class okx(Exchange, ImplicitAPI):
1257
1441
  def fetch_time(self, params={}):
1258
1442
  """
1259
1443
  fetches the current integer timestamp in milliseconds from the exchange server
1260
- :see: https://www.okx.com/docs-v5/en/#public-data-rest-api-get-system-time
1444
+
1445
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-system-time
1446
+
1261
1447
  :param dict [params]: extra parameters specific to the exchange API endpoint
1262
1448
  :returns int: the current integer timestamp in milliseconds from the exchange server
1263
1449
  """
@@ -1271,14 +1457,16 @@ class okx(Exchange, ImplicitAPI):
1271
1457
  # "msg": ""
1272
1458
  # }
1273
1459
  #
1274
- data = self.safe_value(response, 'data', [])
1275
- first = self.safe_value(data, 0, {})
1460
+ data = self.safe_list(response, 'data', [])
1461
+ first = self.safe_dict(data, 0, {})
1276
1462
  return self.safe_integer(first, 'ts')
1277
1463
 
1278
1464
  def fetch_accounts(self, params={}) -> List[Account]:
1279
1465
  """
1280
1466
  fetch all the accounts associated with a profile
1281
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-account-configuration
1467
+
1468
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-account-configuration
1469
+
1282
1470
  :param dict [params]: extra parameters specific to the exchange API endpoint
1283
1471
  :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
1284
1472
  """
@@ -1302,7 +1490,7 @@ class okx(Exchange, ImplicitAPI):
1302
1490
  # "msg": ""
1303
1491
  # }
1304
1492
  #
1305
- data = self.safe_value(response, 'data', [])
1493
+ data = self.safe_list(response, 'data', [])
1306
1494
  result = []
1307
1495
  for i in range(0, len(data)):
1308
1496
  account = data[i]
@@ -1317,14 +1505,21 @@ class okx(Exchange, ImplicitAPI):
1317
1505
  })
1318
1506
  return result
1319
1507
 
1320
- def fetch_markets(self, params={}):
1508
+ def nonce(self):
1509
+ return self.milliseconds() - self.options['timeDifference']
1510
+
1511
+ def fetch_markets(self, params={}) -> List[Market]:
1321
1512
  """
1322
1513
  retrieves data on all markets for okx
1323
- :see: https://www.okx.com/docs-v5/en/#rest-api-public-data-get-instruments
1514
+
1515
+ https://www.okx.com/docs-v5/en/#rest-api-public-data-get-instruments
1516
+
1324
1517
  :param dict [params]: extra parameters specific to the exchange API endpoint
1325
1518
  :returns dict[]: an array of objects representing market data
1326
1519
  """
1327
- types = self.safe_value(self.options, 'fetchMarkets')
1520
+ if self.options['adjustForTimeDifference']:
1521
+ self.load_time_difference()
1522
+ types = self.safe_list(self.options, 'fetchMarkets', [])
1328
1523
  promises = []
1329
1524
  result = []
1330
1525
  for i in range(0, len(types)):
@@ -1334,7 +1529,7 @@ class okx(Exchange, ImplicitAPI):
1334
1529
  result = self.array_concat(result, promises[i])
1335
1530
  return result
1336
1531
 
1337
- def parse_market(self, market) -> Market:
1532
+ def parse_market(self, market: dict) -> Market:
1338
1533
  #
1339
1534
  # {
1340
1535
  # "alias": "", # self_week, next_week, quarter, next_quarter
@@ -1421,7 +1616,7 @@ class okx(Exchange, ImplicitAPI):
1421
1616
  symbol = symbol + '-' + ymd + '-' + strikePrice + '-' + optionType
1422
1617
  optionType = 'put' if (optionType == 'P') else 'call'
1423
1618
  tickSize = self.safe_string(market, 'tickSz')
1424
- fees = self.safe_value_2(self.fees, type, 'trading', {})
1619
+ fees = self.safe_dict_2(self.fees, type, 'trading', {})
1425
1620
  maxLeverage = self.safe_string(market, 'lever', '1')
1426
1621
  maxLeverage = Precise.string_max(maxLeverage, '1')
1427
1622
  maxSpotCost = self.safe_number(market, 'maxMktSz')
@@ -1447,7 +1642,7 @@ class okx(Exchange, ImplicitAPI):
1447
1642
  'contractSize': self.safe_number(market, 'ctVal') if contract else None,
1448
1643
  'expiry': expiry,
1449
1644
  'expiryDatetime': self.iso8601(expiry),
1450
- 'strike': strikePrice,
1645
+ 'strike': self.parse_number(strikePrice),
1451
1646
  'optionType': optionType,
1452
1647
  'created': self.safe_integer(market, 'listTime'),
1453
1648
  'precision': {
@@ -1476,11 +1671,11 @@ class okx(Exchange, ImplicitAPI):
1476
1671
  })
1477
1672
 
1478
1673
  def fetch_markets_by_type(self, type, params={}):
1479
- request = {
1674
+ request: dict = {
1480
1675
  'instType': self.convert_to_instrument_type(type),
1481
1676
  }
1482
1677
  if type == 'option':
1483
- optionsUnderlying = self.safe_value(self.options, 'defaultUnderlying', ['BTC-USD', 'ETH-USD'])
1678
+ optionsUnderlying = self.safe_list(self.options, 'defaultUnderlying', ['BTC-USD', 'ETH-USD'])
1484
1679
  promises = []
1485
1680
  for i in range(0, len(optionsUnderlying)):
1486
1681
  underlying = optionsUnderlying[i]
@@ -1489,8 +1684,8 @@ class okx(Exchange, ImplicitAPI):
1489
1684
  promisesResult = promises
1490
1685
  markets = []
1491
1686
  for i in range(0, len(promisesResult)):
1492
- res = self.safe_value(promisesResult, i, {})
1493
- options = self.safe_value(res, 'data', [])
1687
+ res = self.safe_dict(promisesResult, i, {})
1688
+ options = self.safe_list(res, 'data', [])
1494
1689
  markets = self.array_concat(markets, options)
1495
1690
  return self.parse_markets(markets)
1496
1691
  response = self.publicGetPublicInstruments(self.extend(request, params))
@@ -1527,21 +1722,15 @@ class okx(Exchange, ImplicitAPI):
1527
1722
  # "msg": ""
1528
1723
  # }
1529
1724
  #
1530
- dataResponse = self.safe_value(response, 'data', [])
1725
+ dataResponse = self.safe_list(response, 'data', [])
1531
1726
  return self.parse_markets(dataResponse)
1532
1727
 
1533
- def safe_network(self, networkId):
1534
- networksById = {
1535
- 'Bitcoin': 'BTC',
1536
- 'Omni': 'OMNI',
1537
- 'TRON': 'TRC20',
1538
- }
1539
- return self.safe_string(networksById, networkId, networkId)
1540
-
1541
- def fetch_currencies(self, params={}):
1728
+ def fetch_currencies(self, params={}) -> Currencies:
1542
1729
  """
1543
1730
  fetches all available currencies on an exchange
1544
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-get-currencies
1731
+
1732
+ https://www.okx.com/docs-v5/en/#rest-api-funding-get-currencies
1733
+
1545
1734
  :param dict [params]: extra parameters specific to the exchange API endpoint
1546
1735
  :returns dict: an associative dictionary of currencies
1547
1736
  """
@@ -1601,8 +1790,8 @@ class okx(Exchange, ImplicitAPI):
1601
1790
  # "msg": ""
1602
1791
  # }
1603
1792
  #
1604
- data = self.safe_value(response, 'data', [])
1605
- result = {}
1793
+ data = self.safe_list(response, 'data', [])
1794
+ result: dict = {}
1606
1795
  dataByCurrencyId = self.group_by(data, 'ccy')
1607
1796
  currencyIds = list(dataByCurrencyId.keys())
1608
1797
  for i in range(0, len(currencyIds)):
@@ -1610,24 +1799,24 @@ class okx(Exchange, ImplicitAPI):
1610
1799
  currency = self.safe_currency(currencyId)
1611
1800
  code = currency['code']
1612
1801
  chains = dataByCurrencyId[currencyId]
1613
- networks = {}
1802
+ networks: dict = {}
1614
1803
  currencyActive = False
1615
1804
  depositEnabled = False
1616
1805
  withdrawEnabled = False
1617
1806
  maxPrecision = None
1618
1807
  for j in range(0, len(chains)):
1619
1808
  chain = chains[j]
1620
- canDeposit = self.safe_value(chain, 'canDep')
1809
+ canDeposit = self.safe_bool(chain, 'canDep')
1621
1810
  depositEnabled = canDeposit if (canDeposit) else depositEnabled
1622
- canWithdraw = self.safe_value(chain, 'canWd')
1811
+ canWithdraw = self.safe_bool(chain, 'canWd')
1623
1812
  withdrawEnabled = canWithdraw if (canWithdraw) else withdrawEnabled
1624
- canInternal = self.safe_value(chain, 'canInternal')
1813
+ canInternal = self.safe_bool(chain, 'canInternal')
1625
1814
  active = True if (canDeposit and canWithdraw and canInternal) else False
1626
1815
  currencyActive = active if (active) else currencyActive
1627
1816
  networkId = self.safe_string(chain, 'chain')
1628
1817
  if (networkId is not None) and (networkId.find('-') >= 0):
1629
- parts = networkId.split('-')
1630
- chainPart = self.safe_string(parts, 1, networkId)
1818
+ parts = networkId.split('-')[1:]
1819
+ chainPart = '-'.join(parts)
1631
1820
  networkCode = self.network_id_to_code(chainPart, currency['code'])
1632
1821
  precision = self.parse_precision(self.safe_string(chain, 'wdTickSz'))
1633
1822
  if maxPrecision is None:
@@ -1640,7 +1829,7 @@ class okx(Exchange, ImplicitAPI):
1640
1829
  'active': active,
1641
1830
  'deposit': canDeposit,
1642
1831
  'withdraw': canWithdraw,
1643
- 'fee': self.safe_number(chain, 'minFee'),
1832
+ 'fee': self.safe_number(chain, 'fee'),
1644
1833
  'precision': self.parse_number(precision),
1645
1834
  'limits': {
1646
1835
  'withdraw': {
@@ -1650,9 +1839,9 @@ class okx(Exchange, ImplicitAPI):
1650
1839
  },
1651
1840
  'info': chain,
1652
1841
  }
1653
- firstChain = self.safe_value(chains, 0)
1842
+ firstChain = self.safe_dict(chains, 0, {})
1654
1843
  result[code] = {
1655
- 'info': None,
1844
+ 'info': chains,
1656
1845
  'code': code,
1657
1846
  'id': currencyId,
1658
1847
  'name': self.safe_string(firstChain, 'name'),
@@ -1674,7 +1863,9 @@ class okx(Exchange, ImplicitAPI):
1674
1863
  def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1675
1864
  """
1676
1865
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1677
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-order-book
1866
+
1867
+ https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-order-book
1868
+
1678
1869
  :param str symbol: unified symbol of the market to fetch the order book for
1679
1870
  :param int [limit]: the maximum amount of order book entries to return
1680
1871
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1683,7 +1874,7 @@ class okx(Exchange, ImplicitAPI):
1683
1874
  """
1684
1875
  self.load_markets()
1685
1876
  market = self.market(symbol)
1686
- request = {
1877
+ request: dict = {
1687
1878
  'instId': market['id'],
1688
1879
  }
1689
1880
  method = None
@@ -1719,12 +1910,19 @@ class okx(Exchange, ImplicitAPI):
1719
1910
  # ]
1720
1911
  # }
1721
1912
  #
1722
- data = self.safe_value(response, 'data', [])
1723
- first = self.safe_value(data, 0, {})
1913
+ data = self.safe_list(response, 'data', [])
1914
+ first = self.safe_dict(data, 0, {})
1724
1915
  timestamp = self.safe_integer(first, 'ts')
1725
1916
  return self.parse_order_book(first, symbol, timestamp)
1726
1917
 
1727
- def parse_ticker(self, ticker, market: Market = None) -> Ticker:
1918
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1919
+ #
1920
+ # {
1921
+ # "instType":"SWAP",
1922
+ # "instId":"BTC-USDT-SWAP",
1923
+ # "markPx":"200",
1924
+ # "ts":"1597026383085"
1925
+ # }
1728
1926
  #
1729
1927
  # {
1730
1928
  # "instType": "SPOT",
@@ -1744,6 +1942,16 @@ class okx(Exchange, ImplicitAPI):
1744
1942
  # "sodUtc0": "0.07872",
1745
1943
  # "sodUtc8": "0.07345"
1746
1944
  # }
1945
+ # {
1946
+ # instId: 'LTC-USDT',
1947
+ # idxPx: '65.74',
1948
+ # open24h: '65.37',
1949
+ # high24h: '66.15',
1950
+ # low24h: '64.97',
1951
+ # sodUtc0: '65.68',
1952
+ # sodUtc8: '65.54',
1953
+ # ts: '1728467346900'
1954
+ # },
1747
1955
  #
1748
1956
  timestamp = self.safe_integer(ticker, 'ts')
1749
1957
  marketId = self.safe_string(ticker, 'instId')
@@ -1776,20 +1984,24 @@ class okx(Exchange, ImplicitAPI):
1776
1984
  'average': None,
1777
1985
  'baseVolume': baseVolume,
1778
1986
  'quoteVolume': quoteVolume,
1987
+ 'markPrice': self.safe_string(ticker, 'markPx'),
1988
+ 'indexPrice': self.safe_string(ticker, 'idxPx'),
1779
1989
  'info': ticker,
1780
1990
  }, market)
1781
1991
 
1782
1992
  def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1783
1993
  """
1784
1994
  fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1785
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-ticker
1995
+
1996
+ https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-ticker
1997
+
1786
1998
  :param str symbol: unified symbol of the market to fetch the ticker for
1787
1999
  :param dict [params]: extra parameters specific to the exchange API endpoint
1788
2000
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1789
2001
  """
1790
2002
  self.load_markets()
1791
2003
  market = self.market(symbol)
1792
- request = {
2004
+ request: dict = {
1793
2005
  'instId': market['id'],
1794
2006
  }
1795
2007
  response = self.publicGetMarketTicker(self.extend(request, params))
@@ -1819,20 +2031,33 @@ class okx(Exchange, ImplicitAPI):
1819
2031
  # ]
1820
2032
  # }
1821
2033
  #
1822
- data = self.safe_value(response, 'data', [])
1823
- first = self.safe_value(data, 0, {})
2034
+ data = self.safe_list(response, 'data', [])
2035
+ first = self.safe_dict(data, 0, {})
1824
2036
  return self.parse_ticker(first, market)
1825
2037
 
1826
- def fetch_tickers_by_type(self, type, symbols: Strings = None, params={}):
2038
+ def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
2039
+ """
2040
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
2041
+
2042
+ https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-tickers
2043
+
2044
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
2045
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2046
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
2047
+ """
1827
2048
  self.load_markets()
1828
- request = {
1829
- 'instType': self.convert_to_instrument_type(type),
2049
+ symbols = self.market_symbols(symbols)
2050
+ market = self.get_market_from_symbols(symbols)
2051
+ marketType = None
2052
+ marketType, params = self.handle_market_type_and_params('fetchTickers', market, params)
2053
+ request: dict = {
2054
+ 'instType': self.convert_to_instrument_type(marketType),
1830
2055
  }
1831
- if type == 'option':
1832
- defaultUnderlying = self.safe_value(self.options, 'defaultUnderlying', 'BTC-USD')
2056
+ if marketType == 'option':
2057
+ defaultUnderlying = self.safe_string(self.options, 'defaultUnderlying', 'BTC-USD')
1833
2058
  currencyId = self.safe_string_2(params, 'uly', 'marketId', defaultUnderlying)
1834
2059
  if currencyId is None:
1835
- raise ArgumentsRequired(self.id + ' fetchTickersByType() requires an underlying uly or marketId parameter for options markets')
2060
+ raise ArgumentsRequired(self.id + ' fetchTickers() requires an underlying uly or marketId parameter for options markets')
1836
2061
  else:
1837
2062
  request['uly'] = currencyId
1838
2063
  response = self.publicGetMarketTickers(self.extend(request, params))
@@ -1862,27 +2087,72 @@ class okx(Exchange, ImplicitAPI):
1862
2087
  # ]
1863
2088
  # }
1864
2089
  #
1865
- tickers = self.safe_value(response, 'data', [])
2090
+ tickers = self.safe_list(response, 'data', [])
1866
2091
  return self.parse_tickers(tickers, symbols)
1867
2092
 
1868
- def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
2093
+ def fetch_mark_price(self, symbol: str, params={}) -> Ticker:
2094
+ """
2095
+ fetches mark price for the market
2096
+
2097
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-mark-price
2098
+
2099
+ :param str symbol: unified symbol of the market to fetch the ticker for
2100
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2101
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
2102
+ """
2103
+ self.load_markets()
2104
+ market = self.market(symbol)
2105
+ request: dict = {
2106
+ 'instId': market['id'],
2107
+ }
2108
+ response = self.publicGetPublicMarkPrice(self.extend(request, params))
2109
+ #
2110
+ # {
2111
+ # "code": "0",
2112
+ # "data": [
2113
+ # {
2114
+ # "instId": "ETH-USDT",
2115
+ # "instType": "MARGIN",
2116
+ # "markPx": "2403.98",
2117
+ # "ts": "1728578500703"
2118
+ # }
2119
+ # ],
2120
+ # "msg": ""
2121
+ # }
2122
+ #
2123
+ data = self.safe_list(response, 'data')
2124
+ return self.parse_ticker(self.safe_dict(data, 0), market)
2125
+
2126
+ def fetch_mark_prices(self, symbols: Strings = None, params={}) -> Tickers:
1869
2127
  """
1870
2128
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1871
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-tickers
1872
- :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
2129
+
2130
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-mark-price
2131
+
2132
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1873
2133
  :param dict [params]: extra parameters specific to the exchange API endpoint
1874
2134
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1875
2135
  """
1876
2136
  self.load_markets()
1877
2137
  symbols = self.market_symbols(symbols)
1878
- first = self.safe_string(symbols, 0)
1879
- market = None
1880
- if first is not None:
1881
- market = self.market(first)
1882
- type, query = self.handle_market_type_and_params('fetchTickers', market, params)
1883
- return self.fetch_tickers_by_type(type, symbols, query)
2138
+ market = self.get_market_from_symbols(symbols)
2139
+ marketType = None
2140
+ marketType, params = self.handle_market_type_and_params('fetchTickers', market, params, 'swap')
2141
+ request: dict = {
2142
+ 'instType': self.convert_to_instrument_type(marketType),
2143
+ }
2144
+ if marketType == 'option':
2145
+ defaultUnderlying = self.safe_string(self.options, 'defaultUnderlying', 'BTC-USD')
2146
+ currencyId = self.safe_string_2(params, 'uly', 'marketId', defaultUnderlying)
2147
+ if currencyId is None:
2148
+ raise ArgumentsRequired(self.id + ' fetchMarkPrices() requires an underlying uly or marketId parameter for options markets')
2149
+ else:
2150
+ request['uly'] = currencyId
2151
+ response = self.publicGetPublicMarkPrice(self.extend(request, params))
2152
+ tickers = self.safe_list(response, 'data', [])
2153
+ return self.parse_tickers(tickers, symbols)
1884
2154
 
1885
- def parse_trade(self, trade, market: Market = None) -> Trade:
2155
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1886
2156
  #
1887
2157
  # public fetchTrades
1888
2158
  #
@@ -1975,12 +2245,15 @@ class okx(Exchange, ImplicitAPI):
1975
2245
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1976
2246
  """
1977
2247
  get the list of most recent trades for a particular symbol
1978
- :see: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-trades
1979
- :see: https://www.okx.com/docs-v5/en/#rest-api-public-data-get-option-trades
2248
+
2249
+ https://www.okx.com/docs-v5/en/#rest-api-market-data-get-trades
2250
+ https://www.okx.com/docs-v5/en/#rest-api-public-data-get-option-trades
2251
+
1980
2252
  :param str symbol: unified symbol of the market to fetch trades for
1981
2253
  :param int [since]: timestamp in ms of the earliest trade to fetch
1982
2254
  :param int [limit]: the maximum amount of trades to fetch
1983
2255
  :param dict [params]: extra parameters specific to the exchange API endpoint
2256
+ :param str [params.method]: 'publicGetMarketTrades' or 'publicGetMarketHistoryTrades' default is 'publicGetMarketTrades'
1984
2257
  :param boolean [params.paginate]: *only applies to publicGetMarketHistoryTrades* default False, when True will automatically paginate by calling self endpoint multiple times
1985
2258
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1986
2259
  """
@@ -1990,7 +2263,7 @@ class okx(Exchange, ImplicitAPI):
1990
2263
  if paginate:
1991
2264
  return self.fetch_paginated_call_cursor('fetchTrades', symbol, since, limit, params, 'tradeId', 'after', None, 100)
1992
2265
  market = self.market(symbol)
1993
- request = {
2266
+ request: dict = {
1994
2267
  'instId': market['id'],
1995
2268
  }
1996
2269
  response = None
@@ -2039,7 +2312,7 @@ class okx(Exchange, ImplicitAPI):
2039
2312
  # "msg": ""
2040
2313
  # }
2041
2314
  #
2042
- data = self.safe_value(response, 'data', [])
2315
+ data = self.safe_list(response, 'data', [])
2043
2316
  return self.parse_trades(data, market, since, limit)
2044
2317
 
2045
2318
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
@@ -2071,12 +2344,14 @@ class okx(Exchange, ImplicitAPI):
2071
2344
  def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
2072
2345
  """
2073
2346
  fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
2074
- :see: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks
2075
- :see: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history
2076
- :see: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-mark-price-candlesticks
2077
- :see: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-mark-price-candlesticks-history
2078
- :see: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-index-candlesticks
2079
- :see: https://www.okx.com/docs-v5/en/#rest-api-market-data-get-index-candlesticks-history
2347
+
2348
+ https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks
2349
+ https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history
2350
+ https://www.okx.com/docs-v5/en/#rest-api-market-data-get-mark-price-candlesticks
2351
+ https://www.okx.com/docs-v5/en/#rest-api-market-data-get-mark-price-candlesticks-history
2352
+ https://www.okx.com/docs-v5/en/#rest-api-market-data-get-index-candlesticks
2353
+ https://www.okx.com/docs-v5/en/#rest-api-market-data-get-index-candlesticks-history
2354
+
2080
2355
  :param str symbol: unified symbol of the market to fetch OHLCV data for
2081
2356
  :param str timeframe: the length of time each candle represents
2082
2357
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -2095,7 +2370,7 @@ class okx(Exchange, ImplicitAPI):
2095
2370
  return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 200)
2096
2371
  price = self.safe_string(params, 'price')
2097
2372
  params = self.omit(params, 'price')
2098
- options = self.safe_value(self.options, 'fetchOHLCV', {})
2373
+ options = self.safe_dict(self.options, 'fetchOHLCV', {})
2099
2374
  timezone = self.safe_string(options, 'timezone', 'UTC')
2100
2375
  if limit is None:
2101
2376
  limit = 100 # default 100, max 100
@@ -2103,7 +2378,7 @@ class okx(Exchange, ImplicitAPI):
2103
2378
  bar = self.safe_string(self.timeframes, timeframe, timeframe)
2104
2379
  if (timezone == 'UTC') and (duration >= 21600): # if utc and timeframe >= 6h
2105
2380
  bar += timezone.lower()
2106
- request = {
2381
+ request: dict = {
2107
2382
  'instId': market['id'],
2108
2383
  'bar': bar,
2109
2384
  'limit': limit,
@@ -2155,13 +2430,15 @@ class okx(Exchange, ImplicitAPI):
2155
2430
  # ]
2156
2431
  # }
2157
2432
  #
2158
- data = self.safe_value(response, 'data', [])
2433
+ data = self.safe_list(response, 'data', [])
2159
2434
  return self.parse_ohlcvs(data, market, timeframe, since, limit)
2160
2435
 
2161
2436
  def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2162
2437
  """
2163
2438
  fetches historical funding rate prices
2164
- :see: https://www.okx.com/docs-v5/en/#public-data-rest-api-get-funding-rate-history
2439
+
2440
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-funding-rate-history
2441
+
2165
2442
  :param str symbol: unified symbol of the market to fetch the funding rate history for
2166
2443
  :param int [since]: timestamp in ms of the earliest funding rate to fetch
2167
2444
  :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
@@ -2177,7 +2454,7 @@ class okx(Exchange, ImplicitAPI):
2177
2454
  if paginate:
2178
2455
  return self.fetch_paginated_call_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params, 100)
2179
2456
  market = self.market(symbol)
2180
- request = {
2457
+ request: dict = {
2181
2458
  'instId': market['id'],
2182
2459
  }
2183
2460
  if since is not None:
@@ -2208,7 +2485,7 @@ class okx(Exchange, ImplicitAPI):
2208
2485
  # }
2209
2486
  #
2210
2487
  rates = []
2211
- data = self.safe_value(response, 'data', [])
2488
+ data = self.safe_list(response, 'data', [])
2212
2489
  for i in range(0, len(data)):
2213
2490
  rate = data[i]
2214
2491
  timestamp = self.safe_integer(rate, 'fundingTime')
@@ -2229,11 +2506,11 @@ class okx(Exchange, ImplicitAPI):
2229
2506
  return self.parse_trading_balance(response)
2230
2507
 
2231
2508
  def parse_trading_balance(self, response):
2232
- result = {'info': response}
2233
- data = self.safe_value(response, 'data', [])
2234
- first = self.safe_value(data, 0, {})
2509
+ result: dict = {'info': response}
2510
+ data = self.safe_list(response, 'data', [])
2511
+ first = self.safe_dict(data, 0, {})
2235
2512
  timestamp = self.safe_integer(first, 'uTime')
2236
- details = self.safe_value(first, 'details', [])
2513
+ details = self.safe_list(first, 'details', [])
2237
2514
  for i in range(0, len(details)):
2238
2515
  balance = details[i]
2239
2516
  currencyId = self.safe_string(balance, 'ccy')
@@ -2254,8 +2531,8 @@ class okx(Exchange, ImplicitAPI):
2254
2531
  return self.safe_balance(result)
2255
2532
 
2256
2533
  def parse_funding_balance(self, response):
2257
- result = {'info': response}
2258
- data = self.safe_value(response, 'data', [])
2534
+ result: dict = {'info': response}
2535
+ data = self.safe_list(response, 'data', [])
2259
2536
  for i in range(0, len(data)):
2260
2537
  balance = data[i]
2261
2538
  currencyId = self.safe_string(balance, 'ccy')
@@ -2268,7 +2545,7 @@ class okx(Exchange, ImplicitAPI):
2268
2545
  result[code] = account
2269
2546
  return self.safe_balance(result)
2270
2547
 
2271
- def parse_trading_fee(self, fee, market: Market = None):
2548
+ def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
2272
2549
  # https://www.okx.com/docs-v5/en/#rest-api-account-get-fee-rates
2273
2550
  #
2274
2551
  # {
@@ -2288,19 +2565,23 @@ class okx(Exchange, ImplicitAPI):
2288
2565
  # OKX returns the fees values opposed to other exchanges, so the sign needs to be flipped
2289
2566
  'maker': self.parse_number(Precise.string_neg(self.safe_string_2(fee, 'maker', 'makerU'))),
2290
2567
  'taker': self.parse_number(Precise.string_neg(self.safe_string_2(fee, 'taker', 'takerU'))),
2568
+ 'percentage': None,
2569
+ 'tierBased': None,
2291
2570
  }
2292
2571
 
2293
- def fetch_trading_fee(self, symbol: str, params={}):
2572
+ def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
2294
2573
  """
2295
2574
  fetch the trading fees for a market
2296
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-fee-rates
2575
+
2576
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-fee-rates
2577
+
2297
2578
  :param str symbol: unified market symbol
2298
2579
  :param dict [params]: extra parameters specific to the exchange API endpoint
2299
2580
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
2300
2581
  """
2301
2582
  self.load_markets()
2302
2583
  market = self.market(symbol)
2303
- request = {
2584
+ request: dict = {
2304
2585
  'instType': self.convert_to_instrument_type(market['type']), # SPOT, MARGIN, SWAP, FUTURES, OPTION
2305
2586
  # "instId": market["id"], # only applicable to SPOT/MARGIN
2306
2587
  # "uly": market["id"], # only applicable to FUTURES/SWAP/OPTION
@@ -2331,21 +2612,24 @@ class okx(Exchange, ImplicitAPI):
2331
2612
  # "msg": ""
2332
2613
  # }
2333
2614
  #
2334
- data = self.safe_value(response, 'data', [])
2335
- first = self.safe_value(data, 0, {})
2615
+ data = self.safe_list(response, 'data', [])
2616
+ first = self.safe_dict(data, 0, {})
2336
2617
  return self.parse_trading_fee(first, market)
2337
2618
 
2338
2619
  def fetch_balance(self, params={}) -> Balances:
2339
2620
  """
2340
2621
  query for balance and get the amount of funds available for trading or funds locked in orders
2341
- :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-balance
2342
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-balance
2622
+
2623
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-balance
2624
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-balance
2625
+
2343
2626
  :param dict [params]: extra parameters specific to the exchange API endpoint
2627
+ :param str [params.type]: wallet type, ['funding' or 'trading'] default is 'trading'
2344
2628
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
2345
2629
  """
2346
2630
  self.load_markets()
2347
2631
  marketType, query = self.handle_market_type_and_params('fetchBalance', None, params)
2348
- request = {
2632
+ request: dict = {
2349
2633
  # 'ccy': 'BTC,ETH', # comma-separated list of currency ids
2350
2634
  }
2351
2635
  response = None
@@ -2459,7 +2743,9 @@ class okx(Exchange, ImplicitAPI):
2459
2743
 
2460
2744
  def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
2461
2745
  """
2462
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2746
+
2747
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2748
+
2463
2749
  create a market buy order by providing the symbol and cost
2464
2750
  :param str symbol: unified symbol of the market to create an order in
2465
2751
  :param float cost: how much you want to trade in units of the quote currency
@@ -2470,13 +2756,17 @@ class okx(Exchange, ImplicitAPI):
2470
2756
  market = self.market(symbol)
2471
2757
  if not market['spot']:
2472
2758
  raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot markets only')
2473
- params['createMarketBuyOrderRequiresPrice'] = False
2474
- params['tgtCcy'] = 'quote_ccy'
2475
- return self.create_order(symbol, 'market', 'buy', cost, None, params)
2759
+ req = {
2760
+ 'createMarketBuyOrderRequiresPrice': False,
2761
+ 'tgtCcy': 'quote_ccy',
2762
+ }
2763
+ return self.create_order(symbol, 'market', 'buy', cost, None, self.extend(req, params))
2476
2764
 
2477
2765
  def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}):
2478
2766
  """
2479
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2767
+
2768
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2769
+
2480
2770
  create a market buy order by providing the symbol and cost
2481
2771
  :param str symbol: unified symbol of the market to create an order in
2482
2772
  :param float cost: how much you want to trade in units of the quote currency
@@ -2487,13 +2777,15 @@ class okx(Exchange, ImplicitAPI):
2487
2777
  market = self.market(symbol)
2488
2778
  if not market['spot']:
2489
2779
  raise NotSupported(self.id + ' createMarketSellOrderWithCost() supports spot markets only')
2490
- params['createMarketBuyOrderRequiresPrice'] = False
2491
- params['tgtCcy'] = 'quote_ccy'
2492
- return self.create_order(symbol, 'market', 'sell', cost, None, params)
2780
+ req = {
2781
+ 'createMarketBuyOrderRequiresPrice': False,
2782
+ 'tgtCcy': 'quote_ccy',
2783
+ }
2784
+ return self.create_order(symbol, 'market', 'sell', cost, None, self.extend(req, params))
2493
2785
 
2494
2786
  def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2495
2787
  market = self.market(symbol)
2496
- request = {
2788
+ request: dict = {
2497
2789
  'instId': market['id'],
2498
2790
  # 'ccy': currency['id'], # only applicable to cross MARGIN orders in single-currency margin
2499
2791
  # 'clOrdId': clientOrderId, # up to 32 characters, must be unique
@@ -2536,6 +2828,8 @@ class okx(Exchange, ImplicitAPI):
2536
2828
  takeProfitDefined = (takeProfit is not None)
2537
2829
  trailingPercent = self.safe_string_2(params, 'trailingPercent', 'callbackRatio')
2538
2830
  isTrailingPercentOrder = trailingPercent is not None
2831
+ trigger = (triggerPrice is not None) or (type == 'trigger')
2832
+ isReduceOnly = self.safe_value(params, 'reduceOnly', False)
2539
2833
  defaultMarginMode = self.safe_string_2(self.options, 'defaultMarginMode', 'marginMode', 'cross')
2540
2834
  marginMode = self.safe_string_2(params, 'marginMode', 'tdMode') # cross or isolated, tdMode not ommited so be extended into the request
2541
2835
  margin = False
@@ -2557,6 +2851,20 @@ class okx(Exchange, ImplicitAPI):
2557
2851
  positionSide, params = self.handle_option_and_params(params, 'createOrder', 'positionSide')
2558
2852
  if positionSide is not None:
2559
2853
  request['posSide'] = positionSide
2854
+ else:
2855
+ hedged = None
2856
+ hedged, params = self.handle_option_and_params(params, 'createOrder', 'hedged')
2857
+ if hedged:
2858
+ isBuy = (side == 'buy')
2859
+ isProtective = (takeProfitPrice is not None) or (stopLossPrice is not None) or isReduceOnly
2860
+ if isProtective:
2861
+ # in case of protective orders, the posSide should be opposite of position side
2862
+ # reduceOnly is emulated and not natively supported by the exchange
2863
+ request['posSide'] = 'short' if isBuy else 'long'
2864
+ if isReduceOnly:
2865
+ params = self.omit(params, 'reduceOnly')
2866
+ else:
2867
+ request['posSide'] = 'long' if isBuy else 'short'
2560
2868
  request['tdMode'] = marginMode
2561
2869
  isMarketOrder = type == 'market'
2562
2870
  postOnly = False
@@ -2564,7 +2872,6 @@ class okx(Exchange, ImplicitAPI):
2564
2872
  params = self.omit(params, ['currency', 'ccy', 'marginMode', 'timeInForce', 'stopPrice', 'triggerPrice', 'clientOrderId', 'stopLossPrice', 'takeProfitPrice', 'slOrdPx', 'tpOrdPx', 'margin', 'stopLoss', 'takeProfit', 'trailingPercent'])
2565
2873
  ioc = (timeInForce == 'IOC') or (type == 'ioc')
2566
2874
  fok = (timeInForce == 'FOK') or (type == 'fok')
2567
- trigger = (triggerPrice is not None) or (type == 'trigger')
2568
2875
  conditional = (stopLossPrice is not None) or (takeProfitPrice is not None) or (type == 'conditional')
2569
2876
  marketIOC = (isMarketOrder and ioc) or (type == 'optimal_limit_ioc')
2570
2877
  defaultTgtCcy = self.safe_string(self.options, 'tgtCcy', 'base_ccy')
@@ -2701,14 +3008,16 @@ class okx(Exchange, ImplicitAPI):
2701
3008
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2702
3009
  """
2703
3010
  create a trade order
2704
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
2705
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-multiple-orders
2706
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-place-algo-order
3011
+
3012
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order
3013
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-multiple-orders
3014
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-place-algo-order
3015
+
2707
3016
  :param str symbol: unified symbol of the market to create an order in
2708
3017
  :param str type: 'market' or 'limit'
2709
3018
  :param str side: 'buy' or 'sell'
2710
3019
  :param float amount: how much of currency you want to trade in units of base currency
2711
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
3020
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
2712
3021
  :param dict [params]: extra parameters specific to the exchange API endpoint
2713
3022
  :param bool [params.reduceOnly]: a mark to reduce the position size for margin, swap and future orders
2714
3023
  :param bool [params.postOnly]: True to place a post only order
@@ -2723,6 +3032,7 @@ class okx(Exchange, ImplicitAPI):
2723
3032
  :param str [params.positionSide]: if position mode is one-way: set to 'net', if position mode is hedge-mode: set to 'long' or 'short'
2724
3033
  :param str [params.trailingPercent]: the percent to trail away from the current market price
2725
3034
  :param str [params.tpOrdKind]: 'condition' or 'limit', the default is 'condition'
3035
+ :param bool [params.hedged]: *swap and future only* True for hedged mode, False for one way mode
2726
3036
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2727
3037
  """
2728
3038
  self.load_markets()
@@ -2746,8 +3056,8 @@ class okx(Exchange, ImplicitAPI):
2746
3056
  response = self.privatePostTradeOrderAlgo(request)
2747
3057
  else:
2748
3058
  response = self.privatePostTradeBatchOrders(request)
2749
- data = self.safe_value(response, 'data', [])
2750
- first = self.safe_value(data, 0)
3059
+ data = self.safe_list(response, 'data', [])
3060
+ first = self.safe_dict(data, 0, {})
2751
3061
  order = self.parse_order(first, market)
2752
3062
  order['type'] = type
2753
3063
  order['side'] = side
@@ -2756,8 +3066,11 @@ class okx(Exchange, ImplicitAPI):
2756
3066
  def create_orders(self, orders: List[OrderRequest], params={}):
2757
3067
  """
2758
3068
  create a list of trade orders
2759
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-multiple-orders
3069
+
3070
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-multiple-orders
3071
+
2760
3072
  :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
3073
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2761
3074
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2762
3075
  """
2763
3076
  self.load_markets()
@@ -2769,7 +3082,7 @@ class okx(Exchange, ImplicitAPI):
2769
3082
  side = self.safe_string(rawOrder, 'side')
2770
3083
  amount = self.safe_value(rawOrder, 'amount')
2771
3084
  price = self.safe_value(rawOrder, 'price')
2772
- orderParams = self.safe_value(rawOrder, 'params', {})
3085
+ orderParams = self.safe_dict(rawOrder, 'params', {})
2773
3086
  extendedParams = self.extend(orderParams, params) # the request does not accept extra params since it's a list, so we're extending each order with the common params
2774
3087
  orderRequest = self.create_order_request(marketId, type, side, amount, price, extendedParams)
2775
3088
  ordersRequests.append(orderRequest)
@@ -2796,12 +3109,12 @@ class okx(Exchange, ImplicitAPI):
2796
3109
  # "msg": "",
2797
3110
  # "outTime": "1697979038586493"
2798
3111
  # }
2799
- data = self.safe_value(response, 'data', [])
3112
+ data = self.safe_list(response, 'data', [])
2800
3113
  return self.parse_orders(data)
2801
3114
 
2802
3115
  def edit_order_request(self, id: str, symbol, type, side, amount=None, price=None, params={}):
2803
3116
  market = self.market(symbol)
2804
- request = {
3117
+ request: dict = {
2805
3118
  'instId': market['id'],
2806
3119
  }
2807
3120
  isAlgoOrder = None
@@ -2872,20 +3185,22 @@ class okx(Exchange, ImplicitAPI):
2872
3185
  if not isAlgoOrder:
2873
3186
  if price is not None:
2874
3187
  request['newPx'] = self.price_to_precision(symbol, price)
2875
- params = self.omit(params, ['clOrdId', 'clientOrderId', 'takeProfitPrice', 'stopLossPrice', 'stopLoss', 'takeProfit'])
3188
+ params = self.omit(params, ['clOrdId', 'clientOrderId', 'takeProfitPrice', 'stopLossPrice', 'stopLoss', 'takeProfit', 'postOnly'])
2876
3189
  return self.extend(request, params)
2877
3190
 
2878
3191
  def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
2879
3192
  """
2880
3193
  edit a trade order
2881
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-amend-order
2882
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-amend-algo-order
3194
+
3195
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-amend-order
3196
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-amend-algo-order
3197
+
2883
3198
  :param str id: order id
2884
3199
  :param str symbol: unified symbol of the market to create an order in
2885
3200
  :param str type: 'market' or 'limit'
2886
3201
  :param str side: 'buy' or 'sell'
2887
3202
  :param float amount: how much of the currency you want to trade in units of the base currency
2888
- :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
3203
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
2889
3204
  :param dict [params]: extra parameters specific to the exchange API endpoint
2890
3205
  :param str [params.clientOrderId]: client order id, uses id if not passed
2891
3206
  :param float [params.stopLossPrice]: stop loss trigger price
@@ -2931,8 +3246,8 @@ class okx(Exchange, ImplicitAPI):
2931
3246
  # "msg": ""
2932
3247
  # }
2933
3248
  #
2934
- data = self.safe_value(response, 'data', [])
2935
- first = self.safe_value(data, 0)
3249
+ data = self.safe_list(response, 'data', [])
3250
+ first = self.safe_dict(data, 0, {})
2936
3251
  order = self.parse_order(first, market)
2937
3252
  order['type'] = type
2938
3253
  order['side'] = side
@@ -2941,8 +3256,10 @@ class okx(Exchange, ImplicitAPI):
2941
3256
  def cancel_order(self, id: str, symbol: Str = None, params={}):
2942
3257
  """
2943
3258
  cancels an open order
2944
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-order
2945
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-cancel-algo-order
3259
+
3260
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-order
3261
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-cancel-algo-order
3262
+
2946
3263
  :param str id: order id
2947
3264
  :param str symbol: unified symbol of the market the order was made in
2948
3265
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -2952,14 +3269,14 @@ class okx(Exchange, ImplicitAPI):
2952
3269
  """
2953
3270
  if symbol is None:
2954
3271
  raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
2955
- stop = self.safe_value_2(params, 'stop', 'trigger')
3272
+ trigger = self.safe_value_2(params, 'stop', 'trigger')
2956
3273
  trailing = self.safe_bool(params, 'trailing', False)
2957
- if stop or trailing:
3274
+ if trigger or trailing:
2958
3275
  orderInner = self.cancel_orders([id], symbol, params)
2959
3276
  return self.safe_value(orderInner, 0)
2960
3277
  self.load_markets()
2961
3278
  market = self.market(symbol)
2962
- request = {
3279
+ request: dict = {
2963
3280
  'instId': market['id'],
2964
3281
  # 'ordId': id, # either ordId or clOrdId is required
2965
3282
  # 'clOrdId': clientOrderId,
@@ -2973,12 +3290,12 @@ class okx(Exchange, ImplicitAPI):
2973
3290
  response = self.privatePostTradeCancelOrder(self.extend(request, query))
2974
3291
  # {"code":"0","data":[{"clOrdId":"","ordId":"317251910906576896","sCode":"0","sMsg":""}],"msg":""}
2975
3292
  data = self.safe_value(response, 'data', [])
2976
- order = self.safe_value(data, 0)
3293
+ order = self.safe_dict(data, 0)
2977
3294
  return self.parse_order(order, market)
2978
3295
 
2979
3296
  def parse_ids(self, ids):
2980
3297
  """
2981
- * @ignore
3298
+ @ignore
2982
3299
  :param string[]|str ids: order ids
2983
3300
  :returns str[]: list of order ids
2984
3301
  """
@@ -2990,8 +3307,10 @@ class okx(Exchange, ImplicitAPI):
2990
3307
  def cancel_orders(self, ids, symbol: Str = None, params={}):
2991
3308
  """
2992
3309
  cancel multiple orders
2993
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-multiple-orders
2994
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-cancel-algo-order
3310
+
3311
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-multiple-orders
3312
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-cancel-algo-order
3313
+
2995
3314
  :param str[] ids: order ids
2996
3315
  :param str symbol: unified market symbol
2997
3316
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -3010,9 +3329,9 @@ class okx(Exchange, ImplicitAPI):
3010
3329
  method = self.safe_string(params, 'method', defaultMethod)
3011
3330
  clientOrderIds = self.parse_ids(self.safe_value_2(params, 'clOrdId', 'clientOrderId'))
3012
3331
  algoIds = self.parse_ids(self.safe_value(params, 'algoId'))
3013
- stop = self.safe_value_2(params, 'stop', 'trigger')
3332
+ trigger = self.safe_value_2(params, 'stop', 'trigger')
3014
3333
  trailing = self.safe_bool(params, 'trailing', False)
3015
- if stop or trailing:
3334
+ if trigger or trailing:
3016
3335
  method = 'privatePostTradeCancelAlgos'
3017
3336
  if clientOrderIds is None:
3018
3337
  ids = self.parse_ids(ids)
@@ -3023,7 +3342,7 @@ class okx(Exchange, ImplicitAPI):
3023
3342
  'instId': market['id'],
3024
3343
  })
3025
3344
  for i in range(0, len(ids)):
3026
- if trailing or stop:
3345
+ if trailing or trigger:
3027
3346
  request.append({
3028
3347
  'algoId': ids[i],
3029
3348
  'instId': market['id'],
@@ -3073,11 +3392,116 @@ class okx(Exchange, ImplicitAPI):
3073
3392
  # "msg": ""
3074
3393
  # }
3075
3394
  #
3076
- ordersData = self.safe_value(response, 'data', [])
3395
+ ordersData = self.safe_list(response, 'data', [])
3077
3396
  return self.parse_orders(ordersData, market, None, None, params)
3078
3397
 
3079
- def parse_order_status(self, status):
3080
- statuses = {
3398
+ def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}):
3399
+ """
3400
+ cancel multiple orders for multiple symbols
3401
+
3402
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-multiple-orders
3403
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-post-cancel-algo-order
3404
+
3405
+ :param CancellationRequest[] orders: each order should contain the parameters required by cancelOrder namely id and symbol, example [{"id": "a", "symbol": "BTC/USDT"}, {"id": "b", "symbol": "ETH/USDT"}]
3406
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3407
+ :param boolean [params.trigger]: whether the order is a stop/trigger order
3408
+ :param boolean [params.trailing]: set to True if you want to cancel trailing orders
3409
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3410
+ """
3411
+ self.load_markets()
3412
+ request = []
3413
+ options = self.safe_dict(self.options, 'cancelOrders', {})
3414
+ defaultMethod = self.safe_string(options, 'method', 'privatePostTradeCancelBatchOrders')
3415
+ method = self.safe_string(params, 'method', defaultMethod)
3416
+ trigger = self.safe_bool_2(params, 'stop', 'trigger')
3417
+ trailing = self.safe_bool(params, 'trailing', False)
3418
+ isStopOrTrailing = trigger or trailing
3419
+ if isStopOrTrailing:
3420
+ method = 'privatePostTradeCancelAlgos'
3421
+ for i in range(0, len(orders)):
3422
+ order = orders[i]
3423
+ id = self.safe_string(order, 'id')
3424
+ clientOrderId = self.safe_string_2(order, 'clOrdId', 'clientOrderId')
3425
+ symbol = self.safe_string(order, 'symbol')
3426
+ market = self.market(symbol)
3427
+ idKey = 'ordId'
3428
+ if isStopOrTrailing:
3429
+ idKey = 'algoId'
3430
+ elif clientOrderId is not None:
3431
+ idKey = 'clOrdId'
3432
+ requestItem: dict = {
3433
+ 'instId': market['id'],
3434
+ }
3435
+ requestItem[idKey] = clientOrderId if (clientOrderId is not None) else id
3436
+ request.append(requestItem)
3437
+ response = None
3438
+ if method == 'privatePostTradeCancelAlgos':
3439
+ response = self.privatePostTradeCancelAlgos(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
3440
+ else:
3441
+ response = self.privatePostTradeCancelBatchOrders(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
3442
+ #
3443
+ # {
3444
+ # "code": "0",
3445
+ # "data": [
3446
+ # {
3447
+ # "clOrdId": "e123456789ec4dBC1123456ba123b45e",
3448
+ # "ordId": "405071912345641543",
3449
+ # "sCode": "0",
3450
+ # "sMsg": ""
3451
+ # },
3452
+ # ...
3453
+ # ],
3454
+ # "msg": ""
3455
+ # }
3456
+ #
3457
+ # Algo order
3458
+ #
3459
+ # {
3460
+ # "code": "0",
3461
+ # "data": [
3462
+ # {
3463
+ # "algoId": "431375349042380800",
3464
+ # "sCode": "0",
3465
+ # "sMsg": ""
3466
+ # }
3467
+ # ],
3468
+ # "msg": ""
3469
+ # }
3470
+ #
3471
+ ordersData = self.safe_list(response, 'data', [])
3472
+ return self.parse_orders(ordersData, None, None, None, params)
3473
+
3474
+ def cancel_all_orders_after(self, timeout: Int, params={}):
3475
+ """
3476
+ dead man's switch, cancel all orders after the given timeout
3477
+
3478
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-cancel-all-after
3479
+
3480
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
3481
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3482
+ :returns dict: the api result
3483
+ """
3484
+ self.load_markets()
3485
+ request: dict = {
3486
+ 'timeOut': self.parse_to_int(timeout / 1000) if (timeout > 0) else 0,
3487
+ }
3488
+ response = self.privatePostTradeCancelAllAfter(self.extend(request, params))
3489
+ #
3490
+ # {
3491
+ # "code":"0",
3492
+ # "msg":"",
3493
+ # "data":[
3494
+ # {
3495
+ # "triggerTime":"1587971460",
3496
+ # "ts":"1587971400"
3497
+ # }
3498
+ # ]
3499
+ # }
3500
+ #
3501
+ return response
3502
+
3503
+ def parse_order_status(self, status: Str):
3504
+ statuses: dict = {
3081
3505
  'canceled': 'canceled',
3082
3506
  'order_failed': 'canceled',
3083
3507
  'live': 'open',
@@ -3087,7 +3511,7 @@ class okx(Exchange, ImplicitAPI):
3087
3511
  }
3088
3512
  return self.safe_string(statuses, status, status)
3089
3513
 
3090
- def parse_order(self, order, market: Market = None) -> Order:
3514
+ def parse_order(self, order: dict, market: Market = None) -> Order:
3091
3515
  #
3092
3516
  # createOrder
3093
3517
  #
@@ -3253,7 +3677,6 @@ class okx(Exchange, ImplicitAPI):
3253
3677
  clientOrderId = None # fix empty clientOrderId string
3254
3678
  stopLossPrice = self.safe_number_2(order, 'slTriggerPx', 'slOrdPx')
3255
3679
  takeProfitPrice = self.safe_number_2(order, 'tpTriggerPx', 'tpOrdPx')
3256
- stopPrice = self.safe_number_n(order, ['triggerPx', 'moveTriggerPx'])
3257
3680
  reduceOnlyRaw = self.safe_string(order, 'reduceOnly')
3258
3681
  reduceOnly = False
3259
3682
  if reduceOnly is not None:
@@ -3274,8 +3697,7 @@ class okx(Exchange, ImplicitAPI):
3274
3697
  'price': price,
3275
3698
  'stopLossPrice': stopLossPrice,
3276
3699
  'takeProfitPrice': takeProfitPrice,
3277
- 'stopPrice': stopPrice,
3278
- 'triggerPrice': stopPrice,
3700
+ 'triggerPrice': self.safe_number_n(order, ['triggerPx', 'moveTriggerPx']),
3279
3701
  'average': average,
3280
3702
  'cost': cost,
3281
3703
  'amount': amount,
@@ -3290,8 +3712,10 @@ class okx(Exchange, ImplicitAPI):
3290
3712
  def fetch_order(self, id: str, symbol: Str = None, params={}):
3291
3713
  """
3292
3714
  fetch an order by the id
3293
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-details
3294
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-details
3715
+
3716
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-details
3717
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-details
3718
+
3295
3719
  :param str id: the order id
3296
3720
  :param str symbol: unified market symbol
3297
3721
  :param dict [params]: extra and exchange specific parameters
@@ -3302,7 +3726,7 @@ class okx(Exchange, ImplicitAPI):
3302
3726
  raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
3303
3727
  self.load_markets()
3304
3728
  market = self.market(symbol)
3305
- request = {
3729
+ request: dict = {
3306
3730
  'instId': market['id'],
3307
3731
  # 'clOrdId': 'abcdef12345', # optional, [a-z0-9]{1,32}
3308
3732
  # 'ordId': id,
@@ -3312,8 +3736,8 @@ class okx(Exchange, ImplicitAPI):
3312
3736
  options = self.safe_value(self.options, 'fetchOrder', {})
3313
3737
  defaultMethod = self.safe_string(options, 'method', 'privateGetTradeOrder')
3314
3738
  method = self.safe_string(params, 'method', defaultMethod)
3315
- stop = self.safe_value_2(params, 'stop', 'trigger')
3316
- if stop:
3739
+ trigger = self.safe_value_2(params, 'stop', 'trigger')
3740
+ if trigger:
3317
3741
  method = 'privateGetTradeOrderAlgo'
3318
3742
  if clientOrderId is not None:
3319
3743
  request['algoClOrdId'] = clientOrderId
@@ -3427,19 +3851,21 @@ class okx(Exchange, ImplicitAPI):
3427
3851
  # }
3428
3852
  #
3429
3853
  data = self.safe_value(response, 'data', [])
3430
- order = self.safe_value(data, 0)
3854
+ order = self.safe_dict(data, 0)
3431
3855
  return self.parse_order(order, market)
3432
3856
 
3433
3857
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
3434
3858
  """
3435
3859
  fetch all unfilled currently open orders
3436
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-list
3437
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-list
3860
+
3861
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-list
3862
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-list
3863
+
3438
3864
  :param str symbol: unified market symbol
3439
3865
  :param int [since]: the earliest time in ms to fetch open orders for
3440
3866
  :param int [limit]: the maximum number of open orders structures to retrieve
3441
3867
  :param dict [params]: extra parameters specific to the exchange API endpoint
3442
- :param bool [params.stop]: True if fetching trigger or conditional orders
3868
+ :param bool [params.trigger]: True if fetching trigger or conditional orders
3443
3869
  :param str [params.ordType]: "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
3444
3870
  :param str [params.algoId]: Algo ID "'433845797218942976'"
3445
3871
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
@@ -3451,7 +3877,7 @@ class okx(Exchange, ImplicitAPI):
3451
3877
  paginate, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'paginate')
3452
3878
  if paginate:
3453
3879
  return self.fetch_paginated_call_dynamic('fetchOpenOrders', symbol, since, limit, params)
3454
- request = {
3880
+ request: dict = {
3455
3881
  # 'instType': 'SPOT', # SPOT, MARGIN, SWAP, FUTURES, OPTION
3456
3882
  # 'uly': currency['id'],
3457
3883
  # 'instId': market['id'],
@@ -3472,13 +3898,13 @@ class okx(Exchange, ImplicitAPI):
3472
3898
  defaultMethod = self.safe_string(options, 'method', 'privateGetTradeOrdersPending')
3473
3899
  method = self.safe_string(params, 'method', defaultMethod)
3474
3900
  ordType = self.safe_string(params, 'ordType')
3475
- stop = self.safe_value_2(params, 'stop', 'trigger')
3901
+ trigger = self.safe_value_2(params, 'stop', 'trigger')
3476
3902
  trailing = self.safe_bool(params, 'trailing', False)
3477
- if trailing or stop or (ordType in algoOrderTypes):
3903
+ if trailing or trigger or (ordType in algoOrderTypes):
3478
3904
  method = 'privateGetTradeOrdersAlgoPending'
3479
3905
  if trailing:
3480
3906
  request['ordType'] = 'move_order_stop'
3481
- elif stop and (ordType is None):
3907
+ elif trigger and (ordType is None):
3482
3908
  request['ordType'] = 'trigger'
3483
3909
  query = self.omit(params, ['method', 'stop', 'trigger', 'trailing'])
3484
3910
  response = None
@@ -3581,19 +4007,21 @@ class okx(Exchange, ImplicitAPI):
3581
4007
  # "msg": ""
3582
4008
  # }
3583
4009
  #
3584
- data = self.safe_value(response, 'data', [])
4010
+ data = self.safe_list(response, 'data', [])
3585
4011
  return self.parse_orders(data, market, since, limit)
3586
4012
 
3587
4013
  def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3588
4014
  """
3589
4015
  fetches information on multiple canceled orders made by the user
3590
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-history-last-7-days
3591
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-history
4016
+
4017
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-history-last-7-days
4018
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-history
4019
+
3592
4020
  :param str symbol: unified market symbol of the market orders were made in
3593
4021
  :param int [since]: timestamp in ms of the earliest order, default is None
3594
4022
  :param int [limit]: max number of orders to return, default is None
3595
4023
  :param dict [params]: extra parameters specific to the exchange API endpoint
3596
- :param bool [params.stop]: True if fetching trigger or conditional orders
4024
+ :param bool [params.trigger]: True if fetching trigger or conditional orders
3597
4025
  :param str [params.ordType]: "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
3598
4026
  :param str [params.algoId]: Algo ID "'433845797218942976'"
3599
4027
  :param int [params.until]: timestamp in ms to fetch orders for
@@ -3601,7 +4029,7 @@ class okx(Exchange, ImplicitAPI):
3601
4029
  :returns dict: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3602
4030
  """
3603
4031
  self.load_markets()
3604
- request = {
4032
+ request: dict = {
3605
4033
  # 'instType': type.upper(), # SPOT, MARGIN, SWAP, FUTURES, OPTION
3606
4034
  # 'uly': currency['id'],
3607
4035
  # 'instId': market['id'],
@@ -3628,27 +4056,27 @@ class okx(Exchange, ImplicitAPI):
3628
4056
  defaultMethod = self.safe_string(options, 'method', 'privateGetTradeOrdersHistory')
3629
4057
  method = self.safe_string(params, 'method', defaultMethod)
3630
4058
  ordType = self.safe_string(params, 'ordType')
3631
- stop = self.safe_value_2(params, 'stop', 'trigger')
4059
+ trigger = self.safe_value_2(params, 'stop', 'trigger')
3632
4060
  trailing = self.safe_bool(params, 'trailing', False)
3633
4061
  if trailing:
3634
4062
  method = 'privateGetTradeOrdersAlgoHistory'
3635
4063
  request['ordType'] = 'move_order_stop'
3636
- elif stop or (ordType in algoOrderTypes):
4064
+ elif trigger or (ordType in algoOrderTypes):
3637
4065
  method = 'privateGetTradeOrdersAlgoHistory'
3638
4066
  algoId = self.safe_string(params, 'algoId')
3639
4067
  if algoId is not None:
3640
4068
  request['algoId'] = algoId
3641
4069
  params = self.omit(params, 'algoId')
3642
- if stop:
4070
+ if trigger:
3643
4071
  if ordType is None:
3644
4072
  raise ArgumentsRequired(self.id + ' fetchCanceledOrders() requires an "ordType" string parameter, "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"')
3645
4073
  else:
3646
4074
  if since is not None:
3647
4075
  request['begin'] = since
3648
- until = self.safe_integer_2(query, 'till', 'until')
4076
+ until = self.safe_integer(query, 'until')
3649
4077
  if until is not None:
3650
4078
  request['end'] = until
3651
- query = self.omit(query, ['until', 'till'])
4079
+ query = self.omit(query, ['until'])
3652
4080
  send = self.omit(query, ['method', 'stop', 'trigger', 'trailing'])
3653
4081
  response = None
3654
4082
  if method == 'privateGetTradeOrdersAlgoHistory':
@@ -3754,15 +4182,17 @@ class okx(Exchange, ImplicitAPI):
3754
4182
  # "msg": ""
3755
4183
  # }
3756
4184
  #
3757
- data = self.safe_value(response, 'data', [])
4185
+ data = self.safe_list(response, 'data', [])
3758
4186
  return self.parse_orders(data, market, since, limit)
3759
4187
 
3760
4188
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
3761
4189
  """
3762
4190
  fetches information on multiple closed orders made by the user
3763
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-history-last-7-days
3764
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-history
3765
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-history-last-3-months
4191
+
4192
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-history-last-7-days
4193
+ https://www.okx.com/docs-v5/en/#order-book-trading-algo-trading-get-algo-order-history
4194
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-order-history-last-3-months
4195
+
3766
4196
  :param str symbol: unified market symbol of the market orders were made in
3767
4197
  :param int [since]: the earliest time in ms to fetch orders for
3768
4198
  :param int [limit]: the maximum number of order structures to retrieve
@@ -3781,7 +4211,7 @@ class okx(Exchange, ImplicitAPI):
3781
4211
  paginate, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'paginate')
3782
4212
  if paginate:
3783
4213
  return self.fetch_paginated_call_dynamic('fetchClosedOrders', symbol, since, limit, params)
3784
- request = {
4214
+ request: dict = {
3785
4215
  # 'instType': type.upper(), # SPOT, MARGIN, SWAP, FUTURES, OPTION
3786
4216
  # 'uly': currency['id'],
3787
4217
  # 'instId': market['id'],
@@ -3807,23 +4237,23 @@ class okx(Exchange, ImplicitAPI):
3807
4237
  defaultMethod = self.safe_string(options, 'method', 'privateGetTradeOrdersHistory')
3808
4238
  method = self.safe_string(params, 'method', defaultMethod)
3809
4239
  ordType = self.safe_string(params, 'ordType')
3810
- stop = self.safe_bool_2(params, 'stop', 'trigger')
4240
+ trigger = self.safe_bool_2(params, 'stop', 'trigger')
3811
4241
  trailing = self.safe_bool(params, 'trailing', False)
3812
- if trailing or stop or (ordType in algoOrderTypes):
4242
+ if trailing or trigger or (ordType in algoOrderTypes):
3813
4243
  method = 'privateGetTradeOrdersAlgoHistory'
3814
4244
  request['state'] = 'effective'
3815
4245
  if trailing:
3816
4246
  request['ordType'] = 'move_order_stop'
3817
- elif stop:
4247
+ elif trigger:
3818
4248
  if ordType is None:
3819
4249
  request['ordType'] = 'trigger'
3820
4250
  else:
3821
4251
  if since is not None:
3822
4252
  request['begin'] = since
3823
- until = self.safe_integer_2(query, 'till', 'until')
4253
+ until = self.safe_integer(query, 'until')
3824
4254
  if until is not None:
3825
4255
  request['end'] = until
3826
- query = self.omit(query, ['until', 'till'])
4256
+ query = self.omit(query, ['until'])
3827
4257
  request['state'] = 'filled'
3828
4258
  send = self.omit(query, ['method', 'stop', 'trigger', 'trailing'])
3829
4259
  response = None
@@ -3928,13 +4358,15 @@ class okx(Exchange, ImplicitAPI):
3928
4358
  # "msg": ""
3929
4359
  # }
3930
4360
  #
3931
- data = self.safe_value(response, 'data', [])
4361
+ data = self.safe_list(response, 'data', [])
3932
4362
  return self.parse_orders(data, market, since, limit)
3933
4363
 
3934
4364
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3935
4365
  """
3936
4366
  fetch all trades made by the user
3937
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-transaction-details-last-3-months
4367
+
4368
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-transaction-details-last-3-months
4369
+
3938
4370
  :param str symbol: unified market symbol
3939
4371
  :param int [since]: the earliest time in ms to fetch trades for
3940
4372
  :param int [limit]: the maximum number of trades structures to retrieve
@@ -3948,7 +4380,7 @@ class okx(Exchange, ImplicitAPI):
3948
4380
  paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
3949
4381
  if paginate:
3950
4382
  return self.fetch_paginated_call_dynamic('fetchMyTrades', symbol, since, limit, params)
3951
- request = {
4383
+ request: dict = {
3952
4384
  # 'instType': 'SPOT', # SPOT, MARGIN, SWAP, FUTURES, OPTION
3953
4385
  # 'uly': currency['id'],
3954
4386
  # 'instId': market['id'],
@@ -3994,13 +4426,15 @@ class okx(Exchange, ImplicitAPI):
3994
4426
  # "msg": ""
3995
4427
  # }
3996
4428
  #
3997
- data = self.safe_value(response, 'data', [])
4429
+ data = self.safe_list(response, 'data', [])
3998
4430
  return self.parse_trades(data, market, since, limit, query)
3999
4431
 
4000
4432
  def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4001
4433
  """
4002
4434
  fetch all the trades made from a single order
4003
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-transaction-details-last-3-months
4435
+
4436
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-get-transaction-details-last-3-months
4437
+
4004
4438
  :param str id: order id
4005
4439
  :param str symbol: unified market symbol
4006
4440
  :param int [since]: the earliest time in ms to fetch trades for
@@ -4008,7 +4442,7 @@ class okx(Exchange, ImplicitAPI):
4008
4442
  :param dict [params]: extra parameters specific to the exchange API endpoint
4009
4443
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
4010
4444
  """
4011
- request = {
4445
+ request: dict = {
4012
4446
  # 'instrument_id': market['id'],
4013
4447
  'ordId': id,
4014
4448
  # 'after': '1', # return the page after the specified page number
@@ -4017,31 +4451,33 @@ class okx(Exchange, ImplicitAPI):
4017
4451
  }
4018
4452
  return self.fetch_my_trades(symbol, since, limit, self.extend(request, params))
4019
4453
 
4020
- def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
4454
+ def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
4021
4455
  """
4022
4456
  fetch the history of changes, actions done by the user or operations that altered balance of the user
4023
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-7-days
4024
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-3-months
4025
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-asset-bills-details
4026
- :param str code: unified currency code, default is None
4457
+
4458
+ https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-7-days
4459
+ https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-3-months
4460
+ https://www.okx.com/docs-v5/en/#rest-api-funding-asset-bills-details
4461
+
4462
+ :param str [code]: unified currency code, default is None
4027
4463
  :param int [since]: timestamp in ms of the earliest ledger entry, default is None
4028
- :param int [limit]: max number of ledger entrys to return, default is None
4464
+ :param int [limit]: max number of ledger entries to return, default is None
4029
4465
  :param dict [params]: extra parameters specific to the exchange API endpoint
4030
4466
  :param str [params.marginMode]: 'cross' or 'isolated'
4031
4467
  :param int [params.until]: the latest time in ms to fetch entries for
4032
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
4033
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
4468
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
4469
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
4034
4470
  """
4035
4471
  self.load_markets()
4036
4472
  paginate = False
4037
4473
  paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
4038
4474
  if paginate:
4039
4475
  return self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params)
4040
- options = self.safe_value(self.options, 'fetchLedger', {})
4476
+ options = self.safe_dict(self.options, 'fetchLedger', {})
4041
4477
  method = self.safe_string(options, 'method')
4042
4478
  method = self.safe_string(params, 'method', method)
4043
4479
  params = self.omit(params, 'method')
4044
- request = {
4480
+ request: dict = {
4045
4481
  # 'instType': None, # 'SPOT', 'MARGIN', 'SWAP', 'FUTURES", 'OPTION'
4046
4482
  # 'ccy': None, # currency['id'],
4047
4483
  # 'mgnMode': None, # 'isolated', 'cross'
@@ -4126,11 +4562,11 @@ class okx(Exchange, ImplicitAPI):
4126
4562
  # ]
4127
4563
  # }
4128
4564
  #
4129
- data = self.safe_value(response, 'data', [])
4565
+ data = self.safe_list(response, 'data', [])
4130
4566
  return self.parse_ledger(data, currency, since, limit)
4131
4567
 
4132
4568
  def parse_ledger_entry_type(self, type):
4133
- types = {
4569
+ types: dict = {
4134
4570
  '1': 'transfer', # transfer
4135
4571
  '2': 'trade', # trade
4136
4572
  '3': 'trade', # delivery
@@ -4145,7 +4581,7 @@ class okx(Exchange, ImplicitAPI):
4145
4581
  }
4146
4582
  return self.safe_string(types, type, type)
4147
4583
 
4148
- def parse_ledger_entry(self, item, currency: Currency = None):
4584
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
4149
4585
  #
4150
4586
  # privateGetAccountBills, privateGetAccountBillsArchive
4151
4587
  #
@@ -4182,14 +4618,9 @@ class okx(Exchange, ImplicitAPI):
4182
4618
  # "ts": "1597026383085"
4183
4619
  # }
4184
4620
  #
4185
- id = self.safe_string(item, 'billId')
4186
- account = None
4187
- referenceId = self.safe_string(item, 'ordId')
4188
- referenceAccount = None
4189
- type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
4190
- code = self.safe_currency_code(self.safe_string(item, 'ccy'), currency)
4191
- amountString = self.safe_string(item, 'balChg')
4192
- amount = self.parse_number(amountString)
4621
+ currencyId = self.safe_string(item, 'ccy')
4622
+ code = self.safe_currency_code(currencyId, currency)
4623
+ currency = self.safe_currency(currencyId, currency)
4193
4624
  timestamp = self.safe_integer(item, 'ts')
4194
4625
  feeCostString = self.safe_string(item, 'fee')
4195
4626
  fee = None
@@ -4198,31 +4629,27 @@ class okx(Exchange, ImplicitAPI):
4198
4629
  'cost': self.parse_number(Precise.string_neg(feeCostString)),
4199
4630
  'currency': code,
4200
4631
  }
4201
- before = None
4202
- afterString = self.safe_string(item, 'bal')
4203
- after = self.parse_number(afterString)
4204
- status = 'ok'
4205
4632
  marketId = self.safe_string(item, 'instId')
4206
4633
  symbol = self.safe_symbol(marketId, None, '-')
4207
- return {
4208
- 'id': id,
4634
+ return self.safe_ledger_entry({
4209
4635
  'info': item,
4636
+ 'id': self.safe_string(item, 'billId'),
4210
4637
  'timestamp': timestamp,
4211
4638
  'datetime': self.iso8601(timestamp),
4212
- 'account': account,
4213
- 'referenceId': referenceId,
4214
- 'referenceAccount': referenceAccount,
4215
- 'type': type,
4639
+ 'account': None,
4640
+ 'referenceId': self.safe_string(item, 'ordId'),
4641
+ 'referenceAccount': None,
4642
+ 'type': self.parse_ledger_entry_type(self.safe_string(item, 'type')),
4216
4643
  'currency': code,
4217
4644
  'symbol': symbol,
4218
- 'amount': amount,
4219
- 'before': before, # balance before
4220
- 'after': after, # balance after
4221
- 'status': status,
4645
+ 'amount': self.safe_number(item, 'balChg'),
4646
+ 'before': None,
4647
+ 'after': self.safe_number(item, 'bal'),
4648
+ 'status': 'ok',
4222
4649
  'fee': fee,
4223
- }
4650
+ }, currency)
4224
4651
 
4225
- def parse_deposit_address(self, depositAddress, currency: Currency = None):
4652
+ def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
4226
4653
  #
4227
4654
  # {
4228
4655
  # "addr": "okbtothemoon",
@@ -4310,24 +4737,26 @@ class okx(Exchange, ImplicitAPI):
4310
4737
  networkCode = self.network_id_to_code(network, code)
4311
4738
  self.check_address(address)
4312
4739
  return {
4740
+ 'info': depositAddress,
4313
4741
  'currency': code,
4742
+ 'network': networkCode,
4314
4743
  'address': address,
4315
4744
  'tag': tag,
4316
- 'network': networkCode,
4317
- 'info': depositAddress,
4318
4745
  }
4319
4746
 
4320
- def fetch_deposit_addresses_by_network(self, code: str, params={}):
4747
+ def fetch_deposit_addresses_by_network(self, code: str, params={}) -> List[DepositAddress]:
4321
4748
  """
4322
4749
  fetch a dictionary of addresses for a currency, indexed by network
4323
- :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
4750
+
4751
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
4752
+
4324
4753
  :param str code: unified currency code of the currency for the deposit address
4325
4754
  :param dict [params]: extra parameters specific to the exchange API endpoint
4326
4755
  :returns dict: a dictionary of `address structures <https://docs.ccxt.com/#/?id=address-structure>` indexed by the network
4327
4756
  """
4328
4757
  self.load_markets()
4329
4758
  currency = self.currency(code)
4330
- request = {
4759
+ request: dict = {
4331
4760
  'ccy': currency['id'],
4332
4761
  }
4333
4762
  response = self.privateGetAssetDepositAddress(self.extend(request, params))
@@ -4352,48 +4781,47 @@ class okx(Exchange, ImplicitAPI):
4352
4781
  # ]
4353
4782
  # }
4354
4783
  #
4355
- data = self.safe_value(response, 'data', [])
4784
+ data = self.safe_list(response, 'data', [])
4356
4785
  filtered = self.filter_by(data, 'selected', True)
4357
4786
  parsed = self.parse_deposit_addresses(filtered, [currency['code']], False)
4358
4787
  return self.index_by(parsed, 'network')
4359
4788
 
4360
- def fetch_deposit_address(self, code: str, params={}):
4789
+ def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
4361
4790
  """
4362
4791
  fetch the deposit address for a currency associated with self account
4363
- :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
4792
+
4793
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
4794
+
4364
4795
  :param str code: unified currency code
4365
4796
  :param dict [params]: extra parameters specific to the exchange API endpoint
4797
+ :param str [params.network]: the network name for the deposit address
4366
4798
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
4367
4799
  """
4800
+ self.load_markets()
4368
4801
  rawNetwork = self.safe_string_upper(params, 'network')
4369
- networks = self.safe_value(self.options, 'networks', {})
4370
- network = self.safe_string(networks, rawNetwork, rawNetwork)
4371
4802
  params = self.omit(params, 'network')
4803
+ code = self.safe_currency_code(code)
4804
+ network = self.network_id_to_code(rawNetwork, code)
4372
4805
  response = self.fetch_deposit_addresses_by_network(code, params)
4373
- result = None
4374
- if network is None:
4375
- result = self.safe_value(response, code)
4806
+ if network is not None:
4807
+ result = self.safe_dict(response, network)
4376
4808
  if result is None:
4377
- alias = self.safe_string(networks, code, code)
4378
- result = self.safe_value(response, alias)
4379
- if result is None:
4380
- defaultNetwork = self.safe_string(self.options, 'defaultNetwork', 'ERC20')
4381
- result = self.safe_value(response, defaultNetwork)
4382
- if result is None:
4383
- values = list(response.values())
4384
- result = self.safe_value(values, 0)
4385
- if result is None:
4386
- raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find deposit address for ' + code)
4809
+ raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + network + ' deposit address for ' + code)
4387
4810
  return result
4388
- result = self.safe_value(response, network)
4389
- if result is None:
4390
- raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + network + ' deposit address for ' + code)
4391
- return result
4811
+ codeNetwork = self.network_id_to_code(code, code)
4812
+ if codeNetwork in response:
4813
+ return response[codeNetwork]
4814
+ # if the network is not specified, return the first address
4815
+ keys = list(response.keys())
4816
+ first = self.safe_string(keys, 0)
4817
+ return self.safe_dict(response, first)
4392
4818
 
4393
- def withdraw(self, code: str, amount: float, address, tag=None, params={}):
4819
+ def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
4394
4820
  """
4395
4821
  make a withdrawal
4396
- :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-withdrawal
4822
+
4823
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-withdrawal
4824
+
4397
4825
  :param str code: unified currency code
4398
4826
  :param float amount: the amount to withdraw
4399
4827
  :param str address: the address to withdraw to
@@ -4407,7 +4835,7 @@ class okx(Exchange, ImplicitAPI):
4407
4835
  currency = self.currency(code)
4408
4836
  if (tag is not None) and (len(tag) > 0):
4409
4837
  address = address + ':' + tag
4410
- request = {
4838
+ request: dict = {
4411
4839
  'ccy': currency['id'],
4412
4840
  'toAddr': address,
4413
4841
  'dest': '4', # 2 = OKCoin International, 3 = OKX 4 = others
@@ -4415,7 +4843,7 @@ class okx(Exchange, ImplicitAPI):
4415
4843
  }
4416
4844
  network = self.safe_string(params, 'network') # self line allows the user to specify either ERC20 or ETH
4417
4845
  if network is not None:
4418
- networks = self.safe_value(self.options, 'networks', {})
4846
+ networks = self.safe_dict(self.options, 'networks', {})
4419
4847
  network = self.safe_string(networks, network.upper(), network) # handle ETH>ERC20 alias
4420
4848
  request['chain'] = currency['id'] + '-' + network
4421
4849
  params = self.omit(params, 'network')
@@ -4423,23 +4851,12 @@ class okx(Exchange, ImplicitAPI):
4423
4851
  if fee is None:
4424
4852
  currencies = self.fetch_currencies()
4425
4853
  self.currencies = self.deep_extend(self.currencies, currencies)
4426
- targetNetwork = self.safe_value(currency['networks'], self.network_id_to_code(network), {})
4854
+ targetNetwork = self.safe_dict(currency['networks'], self.network_id_to_code(network), {})
4427
4855
  fee = self.safe_string(targetNetwork, 'fee')
4428
4856
  if fee is None:
4429
4857
  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.')
4430
4858
  request['fee'] = self.number_to_string(fee) # withdrawals to OKCoin or OKX are fee-free, please set 0
4431
- if 'password' in params:
4432
- request['pwd'] = params['password']
4433
- elif 'pwd' in params:
4434
- request['pwd'] = params['pwd']
4435
- else:
4436
- options = self.safe_value(self.options, 'withdraw', {})
4437
- password = self.safe_string_2(options, 'password', 'pwd')
4438
- if password is not None:
4439
- request['pwd'] = password
4440
- query = self.omit(params, ['fee', 'password', 'pwd'])
4441
- if not ('pwd' in request):
4442
- raise ExchangeError(self.id + ' withdraw() requires a password parameter or a pwd parameter, it must be the funding password, not the API passphrase')
4859
+ query = self.omit(params, ['fee'])
4443
4860
  response = self.privatePostAssetWithdrawal(self.extend(request, query))
4444
4861
  #
4445
4862
  # {
@@ -4454,14 +4871,16 @@ class okx(Exchange, ImplicitAPI):
4454
4871
  # ]
4455
4872
  # }
4456
4873
  #
4457
- data = self.safe_value(response, 'data', [])
4458
- transaction = self.safe_value(data, 0)
4874
+ data = self.safe_list(response, 'data', [])
4875
+ transaction = self.safe_dict(data, 0)
4459
4876
  return self.parse_transaction(transaction, currency)
4460
4877
 
4461
4878
  def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
4462
4879
  """
4463
4880
  fetch all deposits made to an account
4464
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-get-deposit-history
4881
+
4882
+ https://www.okx.com/docs-v5/en/#rest-api-funding-get-deposit-history
4883
+
4465
4884
  :param str code: unified currency code
4466
4885
  :param int [since]: the earliest time in ms to fetch deposits for
4467
4886
  :param int [limit]: the maximum number of deposits structures to retrieve
@@ -4475,7 +4894,7 @@ class okx(Exchange, ImplicitAPI):
4475
4894
  paginate, params = self.handle_option_and_params(params, 'fetchDeposits', 'paginate')
4476
4895
  if paginate:
4477
4896
  return self.fetch_paginated_call_dynamic('fetchDeposits', code, since, limit, params)
4478
- request = {
4897
+ request: dict = {
4479
4898
  # 'ccy': currency['id'],
4480
4899
  # 'state': 2, # 0 waiting for confirmation, 1 deposit credited, 2 deposit successful
4481
4900
  # 'after': since,
@@ -4530,20 +4949,22 @@ class okx(Exchange, ImplicitAPI):
4530
4949
  # ]
4531
4950
  # }
4532
4951
  #
4533
- data = self.safe_value(response, 'data', [])
4952
+ data = self.safe_list(response, 'data', [])
4534
4953
  return self.parse_transactions(data, currency, since, limit, params)
4535
4954
 
4536
4955
  def fetch_deposit(self, id: str, code: Str = None, params={}):
4537
4956
  """
4538
4957
  fetch data on a currency deposit via the deposit id
4539
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-get-deposit-history
4958
+
4959
+ https://www.okx.com/docs-v5/en/#rest-api-funding-get-deposit-history
4960
+
4540
4961
  :param str id: deposit id
4541
4962
  :param str code: filter by currency code
4542
4963
  :param dict [params]: extra parameters specific to the exchange API endpoint
4543
4964
  :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
4544
4965
  """
4545
4966
  self.load_markets()
4546
- request = {
4967
+ request: dict = {
4547
4968
  'depId': id,
4548
4969
  }
4549
4970
  currency = None
@@ -4552,13 +4973,15 @@ class okx(Exchange, ImplicitAPI):
4552
4973
  request['ccy'] = currency['id']
4553
4974
  response = self.privateGetAssetDepositHistory(self.extend(request, params))
4554
4975
  data = self.safe_value(response, 'data')
4555
- deposit = self.safe_value(data, 0, {})
4976
+ deposit = self.safe_dict(data, 0, {})
4556
4977
  return self.parse_transaction(deposit, currency)
4557
4978
 
4558
4979
  def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
4559
4980
  """
4560
4981
  fetch all withdrawals made from an account
4561
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-get-withdrawal-history
4982
+
4983
+ https://www.okx.com/docs-v5/en/#rest-api-funding-get-withdrawal-history
4984
+
4562
4985
  :param str code: unified currency code
4563
4986
  :param int [since]: the earliest time in ms to fetch withdrawals for
4564
4987
  :param int [limit]: the maximum number of withdrawals structures to retrieve
@@ -4572,7 +4995,7 @@ class okx(Exchange, ImplicitAPI):
4572
4995
  paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
4573
4996
  if paginate:
4574
4997
  return self.fetch_paginated_call_dynamic('fetchWithdrawals', code, since, limit, params)
4575
- request = {
4998
+ request: dict = {
4576
4999
  # 'ccy': currency['id'],
4577
5000
  # '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
4578
5001
  # 'after': since,
@@ -4619,20 +5042,22 @@ class okx(Exchange, ImplicitAPI):
4619
5042
  # ]
4620
5043
  # }
4621
5044
  #
4622
- data = self.safe_value(response, 'data', [])
5045
+ data = self.safe_list(response, 'data', [])
4623
5046
  return self.parse_transactions(data, currency, since, limit, params)
4624
5047
 
4625
5048
  def fetch_withdrawal(self, id: str, code: Str = None, params={}):
4626
5049
  """
4627
5050
  fetch data on a currency withdrawal via the withdrawal id
4628
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-get-withdrawal-history
5051
+
5052
+ https://www.okx.com/docs-v5/en/#rest-api-funding-get-withdrawal-history
5053
+
4629
5054
  :param str id: withdrawal id
4630
5055
  :param str code: unified currency code of the currency withdrawn, default is None
4631
5056
  :param dict [params]: extra parameters specific to the exchange API endpoint
4632
5057
  :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
4633
5058
  """
4634
5059
  self.load_markets()
4635
- request = {
5060
+ request: dict = {
4636
5061
  'wdId': id,
4637
5062
  }
4638
5063
  currency = None
@@ -4661,11 +5086,11 @@ class okx(Exchange, ImplicitAPI):
4661
5086
  # "msg": ''
4662
5087
  # }
4663
5088
  #
4664
- data = self.safe_value(response, 'data')
4665
- withdrawal = self.safe_value(data, 0, {})
5089
+ data = self.safe_list(response, 'data', [])
5090
+ withdrawal = self.safe_dict(data, 0, {})
4666
5091
  return self.parse_transaction(withdrawal)
4667
5092
 
4668
- def parse_transaction_status(self, status):
5093
+ def parse_transaction_status(self, status: Str):
4669
5094
  #
4670
5095
  # deposit statuses
4671
5096
  #
@@ -4689,7 +5114,7 @@ class okx(Exchange, ImplicitAPI):
4689
5114
  # "5": "awaiting identity verification"
4690
5115
  # }
4691
5116
  #
4692
- statuses = {
5117
+ statuses: dict = {
4693
5118
  '-3': 'pending',
4694
5119
  '-2': 'canceled',
4695
5120
  '-1': 'failed',
@@ -4699,10 +5124,18 @@ class okx(Exchange, ImplicitAPI):
4699
5124
  '3': 'pending',
4700
5125
  '4': 'pending',
4701
5126
  '5': 'pending',
5127
+ '6': 'pending',
5128
+ '7': 'pending',
5129
+ '8': 'pending',
5130
+ '9': 'pending',
5131
+ '10': 'pending',
5132
+ '12': 'pending',
5133
+ '15': 'pending',
5134
+ '16': 'pending',
4702
5135
  }
4703
5136
  return self.safe_string(statuses, status, status)
4704
5137
 
4705
- def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
5138
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
4706
5139
  #
4707
5140
  # withdraw
4708
5141
  #
@@ -4798,7 +5231,9 @@ class okx(Exchange, ImplicitAPI):
4798
5231
  def fetch_leverage(self, symbol: str, params={}) -> Leverage:
4799
5232
  """
4800
5233
  fetch the set leverage for a market
4801
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-get-leverage
5234
+
5235
+ https://www.okx.com/docs-v5/en/#rest-api-account-get-leverage
5236
+
4802
5237
  :param str symbol: unified market symbol
4803
5238
  :param dict [params]: extra parameters specific to the exchange API endpoint
4804
5239
  :param str [params.marginMode]: 'cross' or 'isolated'
@@ -4812,7 +5247,7 @@ class okx(Exchange, ImplicitAPI):
4812
5247
  if (marginMode != 'cross') and (marginMode != 'isolated'):
4813
5248
  raise BadRequest(self.id + ' fetchLeverage() requires a marginMode parameter that must be either cross or isolated')
4814
5249
  market = self.market(symbol)
4815
- request = {
5250
+ request: dict = {
4816
5251
  'instId': market['id'],
4817
5252
  'mgnMode': marginMode,
4818
5253
  }
@@ -4834,7 +5269,7 @@ class okx(Exchange, ImplicitAPI):
4834
5269
  data = self.safe_list(response, 'data', [])
4835
5270
  return self.parse_leverage(data, market)
4836
5271
 
4837
- def parse_leverage(self, leverage, market=None) -> Leverage:
5272
+ def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
4838
5273
  marketId = None
4839
5274
  marginMode = None
4840
5275
  longLeverage = None
@@ -4862,7 +5297,9 @@ class okx(Exchange, ImplicitAPI):
4862
5297
  def fetch_position(self, symbol: str, params={}):
4863
5298
  """
4864
5299
  fetch data on a single open contract trade position
4865
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-get-positions
5300
+
5301
+ https://www.okx.com/docs-v5/en/#rest-api-account-get-positions
5302
+
4866
5303
  :param str symbol: unified market symbol of the market the position is held in, default is None
4867
5304
  :param dict [params]: extra parameters specific to the exchange API endpoint
4868
5305
  :param str [params.instType]: MARGIN, SWAP, FUTURES, OPTION
@@ -4871,7 +5308,7 @@ class okx(Exchange, ImplicitAPI):
4871
5308
  self.load_markets()
4872
5309
  market = self.market(symbol)
4873
5310
  type, query = self.handle_market_type_and_params('fetchPosition', market, params)
4874
- request = {
5311
+ request: dict = {
4875
5312
  # instType str No Instrument type, MARGIN, SWAP, FUTURES, OPTION
4876
5313
  'instId': market['id'],
4877
5314
  # posId str No Single position ID or multiple position IDs(no more than 20) separated with comma
@@ -4925,16 +5362,18 @@ class okx(Exchange, ImplicitAPI):
4925
5362
  # ]
4926
5363
  # }
4927
5364
  #
4928
- data = self.safe_value(response, 'data', [])
4929
- position = self.safe_value(data, 0)
5365
+ data = self.safe_list(response, 'data', [])
5366
+ position = self.safe_dict(data, 0)
4930
5367
  if position is None:
4931
5368
  return None
4932
5369
  return self.parse_position(position, market)
4933
5370
 
4934
5371
  def fetch_positions(self, symbols: Strings = None, params={}):
4935
5372
  """
4936
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-get-positions
4937
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-positions-history history
5373
+
5374
+ https://www.okx.com/docs-v5/en/#rest-api-account-get-positions
5375
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-positions-history history
5376
+
4938
5377
  fetch all open positions
4939
5378
  :param str[]|None symbols: list of unified market symbols
4940
5379
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -4942,7 +5381,7 @@ class okx(Exchange, ImplicitAPI):
4942
5381
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4943
5382
  """
4944
5383
  self.load_markets()
4945
- request = {
5384
+ request: dict = {
4946
5385
  # 'instType': 'MARGIN', # optional string, MARGIN, SWAP, FUTURES, OPTION
4947
5386
  # 'instId': market['id'], # optional string, e.g. 'BTC-USD-190927-5000-C'
4948
5387
  # 'posId': '307173036051017730', # optional string, Single or multiple position IDs(no more than 20) separated with commas
@@ -4956,7 +5395,7 @@ class okx(Exchange, ImplicitAPI):
4956
5395
  marketIdsLength = len(marketIds)
4957
5396
  if marketIdsLength > 0:
4958
5397
  request['instId'] = ','.join(marketIds)
4959
- fetchPositionsOptions = self.safe_value(self.options, 'fetchPositions', {})
5398
+ fetchPositionsOptions = self.safe_dict(self.options, 'fetchPositions', {})
4960
5399
  method = self.safe_string(fetchPositionsOptions, 'method', 'privateGetAccountPositions')
4961
5400
  response = None
4962
5401
  if method == 'privateGetAccountPositionsHistory':
@@ -5009,15 +5448,17 @@ class okx(Exchange, ImplicitAPI):
5009
5448
  # ]
5010
5449
  # }
5011
5450
  #
5012
- positions = self.safe_value(response, 'data', [])
5451
+ positions = self.safe_list(response, 'data', [])
5013
5452
  result = []
5014
5453
  for i in range(0, len(positions)):
5015
5454
  result.append(self.parse_position(positions[i]))
5016
- return self.filter_by_array_positions(result, 'symbol', symbols, False)
5455
+ return self.filter_by_array_positions(result, 'symbol', self.market_symbols(symbols), False)
5017
5456
 
5018
5457
  def fetch_positions_for_symbol(self, symbol: str, params={}):
5019
5458
  """
5020
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-get-positions
5459
+
5460
+ https://www.okx.com/docs-v5/en/#rest-api-account-get-positions
5461
+
5021
5462
  fetch all open positions for specific symbol
5022
5463
  :param str symbol: unified market symbol
5023
5464
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -5026,7 +5467,7 @@ class okx(Exchange, ImplicitAPI):
5026
5467
  """
5027
5468
  return self.fetch_positions([symbol], params)
5028
5469
 
5029
- def parse_position(self, position, market: Market = None):
5470
+ def parse_position(self, position: dict, market: Market = None):
5030
5471
  #
5031
5472
  # {
5032
5473
  # "adl": "3",
@@ -5094,7 +5535,7 @@ class okx(Exchange, ImplicitAPI):
5094
5535
  # }
5095
5536
  #
5096
5537
  marketId = self.safe_string(position, 'instId')
5097
- market = self.safe_market(marketId, market)
5538
+ market = self.safe_market(marketId, market, None, 'contract')
5098
5539
  symbol = market['symbol']
5099
5540
  pos = self.safe_string(position, 'pos') # 'pos' field: One way mode: 0 if position is not open, 1 if open | Two way(hedge) mode: -1 if short, 1 if long, 0 if position is not open
5100
5541
  contractsAbs = Precise.string_abs(pos)
@@ -5187,7 +5628,9 @@ class okx(Exchange, ImplicitAPI):
5187
5628
  def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
5188
5629
  """
5189
5630
  transfer currency internally between wallets on the same account
5190
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-funds-transfer
5631
+
5632
+ https://www.okx.com/docs-v5/en/#rest-api-funding-funds-transfer
5633
+
5191
5634
  :param str code: unified currency code
5192
5635
  :param float amount: amount to transfer
5193
5636
  :param str fromAccount: account to transfer from
@@ -5197,10 +5640,10 @@ class okx(Exchange, ImplicitAPI):
5197
5640
  """
5198
5641
  self.load_markets()
5199
5642
  currency = self.currency(code)
5200
- accountsByType = self.safe_value(self.options, 'accountsByType', {})
5643
+ accountsByType = self.safe_dict(self.options, 'accountsByType', {})
5201
5644
  fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
5202
5645
  toId = self.safe_string(accountsByType, toAccount, toAccount)
5203
- request = {
5646
+ request: dict = {
5204
5647
  'ccy': currency['id'],
5205
5648
  'amt': self.currency_to_precision(code, amount),
5206
5649
  '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
@@ -5237,11 +5680,11 @@ class okx(Exchange, ImplicitAPI):
5237
5680
  # ]
5238
5681
  # }
5239
5682
  #
5240
- data = self.safe_value(response, 'data', [])
5241
- rawTransfer = self.safe_value(data, 0, {})
5683
+ data = self.safe_list(response, 'data', [])
5684
+ rawTransfer = self.safe_dict(data, 0, {})
5242
5685
  return self.parse_transfer(rawTransfer, currency)
5243
5686
 
5244
- def parse_transfer(self, transfer, currency: Currency = None):
5687
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
5245
5688
  #
5246
5689
  # transfer
5247
5690
  #
@@ -5300,7 +5743,7 @@ class okx(Exchange, ImplicitAPI):
5300
5743
  amount = self.safe_number(transfer, 'amt')
5301
5744
  fromAccountId = self.safe_string(transfer, 'from')
5302
5745
  toAccountId = self.safe_string(transfer, 'to')
5303
- accountsById = self.safe_value(self.options, 'accountsById', {})
5746
+ accountsById = self.safe_dict(self.options, 'accountsById', {})
5304
5747
  timestamp = self.safe_integer(transfer, 'ts')
5305
5748
  balanceChange = self.safe_string(transfer, 'sz')
5306
5749
  if balanceChange is not None:
@@ -5317,15 +5760,15 @@ class okx(Exchange, ImplicitAPI):
5317
5760
  'status': self.parse_transfer_status(self.safe_string(transfer, 'state')),
5318
5761
  }
5319
5762
 
5320
- def parse_transfer_status(self, status):
5321
- statuses = {
5763
+ def parse_transfer_status(self, status: Str) -> Str:
5764
+ statuses: dict = {
5322
5765
  'success': 'ok',
5323
5766
  }
5324
5767
  return self.safe_string(statuses, status, status)
5325
5768
 
5326
- def fetch_transfer(self, id: str, code: Str = None, params={}):
5769
+ def fetch_transfer(self, id: str, code: Str = None, params={}) -> TransferEntry:
5327
5770
  self.load_markets()
5328
- request = {
5771
+ request: dict = {
5329
5772
  'transId': id,
5330
5773
  # 'type': 0, # default is 0 transfer within account, 1 master to sub, 2 sub to master
5331
5774
  }
@@ -5350,14 +5793,16 @@ class okx(Exchange, ImplicitAPI):
5350
5793
  # "msg": ""
5351
5794
  # }
5352
5795
  #
5353
- data = self.safe_value(response, 'data', [])
5354
- transfer = self.safe_value(data, 0)
5796
+ data = self.safe_list(response, 'data', [])
5797
+ transfer = self.safe_dict(data, 0)
5355
5798
  return self.parse_transfer(transfer)
5356
5799
 
5357
- def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
5800
+ def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[TransferEntry]:
5358
5801
  """
5359
5802
  fetch a history of internal transfers made on an account
5360
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-3-months
5803
+
5804
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-3-months
5805
+
5361
5806
  :param str code: unified currency code of the currency transferred
5362
5807
  :param int [since]: the earliest time in ms to fetch transfers for
5363
5808
  :param int [limit]: the maximum number of transfers structures to retrieve
@@ -5366,7 +5811,7 @@ class okx(Exchange, ImplicitAPI):
5366
5811
  """
5367
5812
  self.load_markets()
5368
5813
  currency = None
5369
- request = {
5814
+ request: dict = {
5370
5815
  'type': '1', # https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-3-months
5371
5816
  }
5372
5817
  if code is not None:
@@ -5409,7 +5854,7 @@ class okx(Exchange, ImplicitAPI):
5409
5854
  # "msg": ""
5410
5855
  # }
5411
5856
  #
5412
- transfers = self.safe_value(response, 'data', [])
5857
+ transfers = self.safe_list(response, 'data', [])
5413
5858
  return self.parse_transfers(transfers, currency, since, limit, params)
5414
5859
 
5415
5860
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
@@ -5439,7 +5884,7 @@ class okx(Exchange, ImplicitAPI):
5439
5884
  if clientOrderId is None:
5440
5885
  params['clOrdId'] = brokerId + self.uuid16()
5441
5886
  params['tag'] = brokerId
5442
- timestamp = self.iso8601(self.milliseconds())
5887
+ timestamp = self.iso8601(self.nonce())
5443
5888
  headers = {
5444
5889
  'OK-ACCESS-KEY': self.apiKey,
5445
5890
  'OK-ACCESS-PASSPHRASE': self.password,
@@ -5463,7 +5908,7 @@ class okx(Exchange, ImplicitAPI):
5463
5908
  headers['OK-ACCESS-SIGN'] = signature
5464
5909
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
5465
5910
 
5466
- def parse_funding_rate(self, contract, market: Market = None):
5911
+ def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
5467
5912
  #
5468
5913
  # {
5469
5914
  # "fundingRate": "0.00027815",
@@ -5473,6 +5918,22 @@ class okx(Exchange, ImplicitAPI):
5473
5918
  # "nextFundingRate": "0.00017",
5474
5919
  # "nextFundingTime": "1634284800000"
5475
5920
  # }
5921
+ # ws
5922
+ # {
5923
+ # "fundingRate":"0.0001875391284828",
5924
+ # "fundingTime":"1700726400000",
5925
+ # "instId":"BTC-USD-SWAP",
5926
+ # "instType":"SWAP",
5927
+ # "method": "next_period",
5928
+ # "maxFundingRate":"0.00375",
5929
+ # "minFundingRate":"-0.00375",
5930
+ # "nextFundingRate":"0.0002608059239328",
5931
+ # "nextFundingTime":"1700755200000",
5932
+ # "premium": "0.0001233824646391",
5933
+ # "settFundingRate":"0.0001699799259033",
5934
+ # "settState":"settled",
5935
+ # "ts":"1700724675402"
5936
+ # }
5476
5937
  #
5477
5938
  # in the response above nextFundingRate is actually two funding rates from now
5478
5939
  #
@@ -5481,6 +5942,9 @@ class okx(Exchange, ImplicitAPI):
5481
5942
  symbol = self.safe_symbol(marketId, market)
5482
5943
  nextFundingRate = self.safe_number(contract, 'nextFundingRate')
5483
5944
  fundingTime = self.safe_integer(contract, 'fundingTime')
5945
+ fundingTimeString = self.safe_string(contract, 'fundingTime')
5946
+ nextFundingTimeString = self.safe_string(contract, 'nextFundingRate')
5947
+ millisecondsInterval = Precise.string_sub(nextFundingTimeString, fundingTimeString)
5484
5948
  # https://www.okx.com/support/hc/en-us/articles/360053909272-Ⅸ-Introduction-to-perpetual-swap-funding-fee
5485
5949
  # > The current interest is 0.
5486
5950
  return {
@@ -5501,12 +5965,37 @@ class okx(Exchange, ImplicitAPI):
5501
5965
  'previousFundingRate': None,
5502
5966
  'previousFundingTimestamp': None,
5503
5967
  'previousFundingDatetime': None,
5968
+ 'interval': self.parse_funding_interval(millisecondsInterval),
5504
5969
  }
5505
5970
 
5506
- def fetch_funding_rate(self, symbol: str, params={}):
5971
+ def parse_funding_interval(self, interval):
5972
+ intervals: dict = {
5973
+ '3600000': '1h',
5974
+ '14400000': '4h',
5975
+ '28800000': '8h',
5976
+ '57600000': '16h',
5977
+ '86400000': '24h',
5978
+ }
5979
+ return self.safe_string(intervals, interval, interval)
5980
+
5981
+ def fetch_funding_interval(self, symbol: str, params={}) -> FundingRate:
5982
+ """
5983
+ fetch the current funding rate interval
5984
+
5985
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-funding-rate
5986
+
5987
+ :param str symbol: unified market symbol
5988
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5989
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
5990
+ """
5991
+ return self.fetch_funding_rate(symbol, params)
5992
+
5993
+ def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
5507
5994
  """
5508
5995
  fetch the current funding rate
5509
- :see: https://www.okx.com/docs-v5/en/#public-data-rest-api-get-funding-rate
5996
+
5997
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-funding-rate
5998
+
5510
5999
  :param str symbol: unified market symbol
5511
6000
  :param dict [params]: extra parameters specific to the exchange API endpoint
5512
6001
  :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
@@ -5515,7 +6004,7 @@ class okx(Exchange, ImplicitAPI):
5515
6004
  market = self.market(symbol)
5516
6005
  if not market['swap']:
5517
6006
  raise ExchangeError(self.id + ' fetchFundingRate() is only valid for swap markets')
5518
- request = {
6007
+ request: dict = {
5519
6008
  'instId': market['id'],
5520
6009
  }
5521
6010
  response = self.publicGetPublicFundingRate(self.extend(request, params))
@@ -5535,14 +6024,16 @@ class okx(Exchange, ImplicitAPI):
5535
6024
  # "msg": ""
5536
6025
  # }
5537
6026
  #
5538
- data = self.safe_value(response, 'data', [])
5539
- entry = self.safe_value(data, 0, {})
6027
+ data = self.safe_list(response, 'data', [])
6028
+ entry = self.safe_dict(data, 0, {})
5540
6029
  return self.parse_funding_rate(entry, market)
5541
6030
 
5542
6031
  def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
5543
6032
  """
5544
6033
  fetch the history of funding payments paid and received on self account
5545
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-3-months
6034
+
6035
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-3-months
6036
+
5546
6037
  :param str symbol: unified market symbol
5547
6038
  :param int [since]: the earliest time in ms to fetch funding history for
5548
6039
  :param int [limit]: the maximum number of funding history structures to retrieve
@@ -5550,7 +6041,7 @@ class okx(Exchange, ImplicitAPI):
5550
6041
  :returns dict: a `funding history structure <https://docs.ccxt.com/#/?id=funding-history-structure>`
5551
6042
  """
5552
6043
  self.load_markets()
5553
- request = {
6044
+ request: dict = {
5554
6045
  # 'instType': 'SPOT', # SPOT, MARGIN, SWAP, FUTURES, OPTION
5555
6046
  # 'ccy': currency['id'],
5556
6047
  # 'mgnMode': 'isolated', # isolated, cross
@@ -5668,7 +6159,7 @@ class okx(Exchange, ImplicitAPI):
5668
6159
  # "type": "8"
5669
6160
  # }
5670
6161
  #
5671
- data = self.safe_value(response, 'data', [])
6162
+ data = self.safe_list(response, 'data', [])
5672
6163
  result = []
5673
6164
  for i in range(0, len(data)):
5674
6165
  entry = data[i]
@@ -5692,12 +6183,14 @@ class okx(Exchange, ImplicitAPI):
5692
6183
  def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
5693
6184
  """
5694
6185
  set the level of leverage for a market
5695
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-set-leverage
6186
+
6187
+ https://www.okx.com/docs-v5/en/#rest-api-account-set-leverage
6188
+
5696
6189
  :param float leverage: the rate of leverage
5697
6190
  :param str symbol: unified market symbol
5698
6191
  :param dict [params]: extra parameters specific to the exchange API endpoint
5699
6192
  :param str [params.marginMode]: 'cross' or 'isolated'
5700
- :param str [params.posSide]: 'long' or 'short' for isolated margin long/short mode on futures and swap markets
6193
+ :param str [params.posSide]: 'long' or 'short' or 'net' for isolated margin long/short mode on futures and swap markets, default is 'net'
5701
6194
  :returns dict: response from the exchange
5702
6195
  """
5703
6196
  if symbol is None:
@@ -5714,17 +6207,16 @@ class okx(Exchange, ImplicitAPI):
5714
6207
  marginMode = self.safe_string(params, 'mgnMode', 'cross') # cross marginMode
5715
6208
  if (marginMode != 'cross') and (marginMode != 'isolated'):
5716
6209
  raise BadRequest(self.id + ' setLeverage() requires a marginMode parameter that must be either cross or isolated')
5717
- request = {
6210
+ request: dict = {
5718
6211
  'lever': leverage,
5719
6212
  'mgnMode': marginMode,
5720
6213
  'instId': market['id'],
5721
6214
  }
5722
- posSide = self.safe_string(params, 'posSide')
6215
+ posSide = self.safe_string(params, 'posSide', 'net')
5723
6216
  if marginMode == 'isolated':
5724
- if posSide is None:
5725
- raise ArgumentsRequired(self.id + ' setLeverage() requires a posSide argument for isolated margin')
5726
6217
  if posSide != 'long' and posSide != 'short' and posSide != 'net':
5727
6218
  raise BadRequest(self.id + ' setLeverage() requires the posSide argument to be either "long", "short" or "net"')
6219
+ request['posSide'] = posSide
5728
6220
  response = self.privatePostAccountSetLeverage(self.extend(request, params))
5729
6221
  #
5730
6222
  # {
@@ -5742,10 +6234,44 @@ class okx(Exchange, ImplicitAPI):
5742
6234
  #
5743
6235
  return response
5744
6236
 
6237
+ def fetch_position_mode(self, symbol: Str = None, params={}):
6238
+ """
6239
+
6240
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-account-configuration
6241
+
6242
+ fetchs the position mode, hedged or one way, hedged for binance is set identically for all linear markets or all inverse markets
6243
+ :param str symbol: unified symbol of the market to fetch the order book for
6244
+ :param dict [params]: extra parameters specific to the exchange API endpoint
6245
+ :param str [params.accountId]: if you have multiple accounts, you must specify the account id to fetch the position mode
6246
+ :returns dict: an object detailing whether the market is in hedged or one-way mode
6247
+ """
6248
+ accounts = self.fetch_accounts()
6249
+ length = len(accounts)
6250
+ selectedAccount = None
6251
+ if length > 1:
6252
+ accountId = self.safe_string(params, 'accountId')
6253
+ if accountId is None:
6254
+ accountIds = self.get_list_from_object_values(accounts, 'id')
6255
+ raise ExchangeError(self.id + ' fetchPositionMode() can not detect position mode, because you have multiple accounts. Set params["accountId"] to desired id from: ' + ', '.join(accountIds))
6256
+ else:
6257
+ accountsById = self.index_by(accounts, 'id')
6258
+ selectedAccount = self.safe_dict(accountsById, accountId)
6259
+ else:
6260
+ selectedAccount = accounts[0]
6261
+ mainAccount = selectedAccount['info']
6262
+ posMode = self.safe_string(mainAccount, 'posMode') # long_short_mode, net_mode
6263
+ isHedged = posMode == 'long_short_mode'
6264
+ return {
6265
+ 'info': mainAccount,
6266
+ 'hedged': isHedged,
6267
+ }
6268
+
5745
6269
  def set_position_mode(self, hedged: bool, symbol: Str = None, params={}):
5746
6270
  """
5747
6271
  set hedged to True or False for a market
5748
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-set-position-mode
6272
+
6273
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-set-position-mode
6274
+
5749
6275
  :param bool hedged: set to True to use long_short_mode, False for net_mode
5750
6276
  :param str symbol: not used by okx setPositionMode
5751
6277
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -5756,7 +6282,7 @@ class okx(Exchange, ImplicitAPI):
5756
6282
  hedgeMode = 'long_short_mode'
5757
6283
  else:
5758
6284
  hedgeMode = 'net_mode'
5759
- request = {
6285
+ request: dict = {
5760
6286
  'posMode': hedgeMode,
5761
6287
  }
5762
6288
  response = self.privatePostAccountSetPositionMode(self.extend(request, params))
@@ -5776,7 +6302,9 @@ class okx(Exchange, ImplicitAPI):
5776
6302
  def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
5777
6303
  """
5778
6304
  set margin mode to 'cross' or 'isolated'
5779
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-set-leverage
6305
+
6306
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-set-leverage
6307
+
5780
6308
  :param str marginMode: 'cross' or 'isolated'
5781
6309
  :param str symbol: unified market symbol
5782
6310
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -5796,7 +6324,7 @@ class okx(Exchange, ImplicitAPI):
5796
6324
  if (lever is None) or (lever < 1) or (lever > 125):
5797
6325
  raise BadRequest(self.id + ' setMarginMode() params["lever"] should be between 1 and 125')
5798
6326
  params = self.omit(params, ['leverage'])
5799
- request = {
6327
+ request: dict = {
5800
6328
  'lever': lever,
5801
6329
  'mgnMode': marginMode,
5802
6330
  'instId': market['id'],
@@ -5818,10 +6346,12 @@ class okx(Exchange, ImplicitAPI):
5818
6346
  #
5819
6347
  return response
5820
6348
 
5821
- def fetch_cross_borrow_rates(self, params={}):
6349
+ def fetch_cross_borrow_rates(self, params={}) -> CrossBorrowRates:
5822
6350
  """
5823
6351
  fetch the borrow interest rates of all currencies
5824
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-interest-rate
6352
+
6353
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-interest-rate
6354
+
5825
6355
  :param dict [params]: extra parameters specific to the exchange API endpoint
5826
6356
  :returns dict: a list of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>`
5827
6357
  """
@@ -5839,23 +6369,25 @@ class okx(Exchange, ImplicitAPI):
5839
6369
  # ],
5840
6370
  # }
5841
6371
  #
5842
- data = self.safe_value(response, 'data', [])
6372
+ data = self.safe_list(response, 'data', [])
5843
6373
  rates = []
5844
6374
  for i in range(0, len(data)):
5845
6375
  rates.append(self.parse_borrow_rate(data[i]))
5846
6376
  return rates
5847
6377
 
5848
- def fetch_cross_borrow_rate(self, code: str, params={}):
6378
+ def fetch_cross_borrow_rate(self, code: str, params={}) -> CrossBorrowRate:
5849
6379
  """
5850
6380
  fetch the rate of interest to borrow a currency for margin trading
5851
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-interest-rate
6381
+
6382
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-interest-rate
6383
+
5852
6384
  :param str code: unified currency code
5853
6385
  :param dict [params]: extra parameters specific to the exchange API endpoint
5854
6386
  :returns dict: a `borrow rate structure <https://docs.ccxt.com/#/?id=borrow-rate-structure>`
5855
6387
  """
5856
6388
  self.load_markets()
5857
6389
  currency = self.currency(code)
5858
- request = {
6390
+ request: dict = {
5859
6391
  'ccy': currency['id'],
5860
6392
  }
5861
6393
  response = self.privateGetAccountInterestRate(self.extend(request, params))
@@ -5872,8 +6404,8 @@ class okx(Exchange, ImplicitAPI):
5872
6404
  # "msg": ""
5873
6405
  # }
5874
6406
  #
5875
- data = self.safe_value(response, 'data')
5876
- rate = self.safe_value(data, 0)
6407
+ data = self.safe_list(response, 'data', [])
6408
+ rate = self.safe_dict(data, 0, {})
5877
6409
  return self.parse_borrow_rate(rate)
5878
6410
 
5879
6411
  def parse_borrow_rate(self, info, currency: Currency = None):
@@ -5908,7 +6440,7 @@ class okx(Exchange, ImplicitAPI):
5908
6440
  # ...
5909
6441
  # ]
5910
6442
  #
5911
- borrowRateHistories = {}
6443
+ borrowRateHistories: dict = {}
5912
6444
  for i in range(0, len(response)):
5913
6445
  item = response[i]
5914
6446
  code = self.safe_currency_code(self.safe_string(item, 'ccy'))
@@ -5923,19 +6455,12 @@ class okx(Exchange, ImplicitAPI):
5923
6455
  borrowRateHistories[code] = self.filter_by_currency_since_limit(borrowRateHistories[code], code, since, limit)
5924
6456
  return borrowRateHistories
5925
6457
 
5926
- def parse_borrow_rate_history(self, response, code, since, limit):
5927
- result = []
5928
- for i in range(0, len(response)):
5929
- item = response[i]
5930
- borrowRate = self.parse_borrow_rate(item)
5931
- result.append(borrowRate)
5932
- sorted = self.sort_by(result, 'timestamp')
5933
- return self.filter_by_currency_since_limit(sorted, code, since, limit)
5934
-
5935
6458
  def fetch_borrow_rate_histories(self, codes=None, since: Int = None, limit: Int = None, params={}):
5936
6459
  """
5937
6460
  retrieves a history of a multiple currencies borrow interest rate at specific time slots, returns all currencies if no symbols passed, default is None
5938
- :see: https://www.okx.com/docs-v5/en/#financial-product-savings-get-public-borrow-history-public
6461
+
6462
+ https://www.okx.com/docs-v5/en/#financial-product-savings-get-public-borrow-history-public
6463
+
5939
6464
  :param str[]|None codes: list of unified currency codes, default is None
5940
6465
  :param int [since]: timestamp in ms of the earliest borrowRate, default is None
5941
6466
  :param int [limit]: max number of borrow rate prices to return, default is None
@@ -5943,7 +6468,7 @@ class okx(Exchange, ImplicitAPI):
5943
6468
  :returns dict: a dictionary of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>` indexed by the market symbol
5944
6469
  """
5945
6470
  self.load_markets()
5946
- request = {
6471
+ request: dict = {
5947
6472
  # 'ccy': currency['id'],
5948
6473
  # 'after': self.milliseconds(), # Pagination of data to return records earlier than the requested ts,
5949
6474
  # 'before': since, # Pagination of data to return records newer than the requested ts,
@@ -5968,13 +6493,15 @@ class okx(Exchange, ImplicitAPI):
5968
6493
  # "msg": ""
5969
6494
  # }
5970
6495
  #
5971
- data = self.safe_value(response, 'data')
6496
+ data = self.safe_list(response, 'data', [])
5972
6497
  return self.parse_borrow_rate_histories(data, codes, since, limit)
5973
6498
 
5974
6499
  def fetch_borrow_rate_history(self, code: str, since: Int = None, limit: Int = None, params={}):
5975
6500
  """
5976
6501
  retrieves a history of a currencies borrow interest rate at specific time slots
5977
- :see: https://www.okx.com/docs-v5/en/#financial-product-savings-get-public-borrow-history-public
6502
+
6503
+ https://www.okx.com/docs-v5/en/#financial-product-savings-get-public-borrow-history-public
6504
+
5978
6505
  :param str code: unified currency code
5979
6506
  :param int [since]: timestamp for the earliest borrow rate
5980
6507
  :param int [limit]: the maximum number of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>` to retrieve
@@ -5983,7 +6510,7 @@ class okx(Exchange, ImplicitAPI):
5983
6510
  """
5984
6511
  self.load_markets()
5985
6512
  currency = self.currency(code)
5986
- request = {
6513
+ request: dict = {
5987
6514
  'ccy': currency['id'],
5988
6515
  # 'after': self.milliseconds(), # Pagination of data to return records earlier than the requested ts,
5989
6516
  # 'before': since, # Pagination of data to return records newer than the requested ts,
@@ -6008,15 +6535,15 @@ class okx(Exchange, ImplicitAPI):
6008
6535
  # "msg": ""
6009
6536
  # }
6010
6537
  #
6011
- data = self.safe_value(response, 'data')
6538
+ data = self.safe_list(response, 'data', [])
6012
6539
  return self.parse_borrow_rate_history(data, code, since, limit)
6013
6540
 
6014
- def modify_margin_helper(self, symbol: str, amount, type, params={}):
6541
+ def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
6015
6542
  self.load_markets()
6016
6543
  market = self.market(symbol)
6017
6544
  posSide = self.safe_string(params, 'posSide', 'net')
6018
6545
  params = self.omit(params, ['posSide'])
6019
- request = {
6546
+ request: dict = {
6020
6547
  'instId': market['id'],
6021
6548
  'amt': amount,
6022
6549
  'type': type,
@@ -6037,32 +6564,92 @@ class okx(Exchange, ImplicitAPI):
6037
6564
  # "msg": ""
6038
6565
  # }
6039
6566
  #
6040
- return self.parse_margin_modification(response, market)
6041
-
6042
- def parse_margin_modification(self, data, market: Market = None):
6043
- innerData = self.safe_value(data, 'data', [])
6044
- entry = self.safe_value(innerData, 0, {})
6045
- errorCode = self.safe_string(data, 'code')
6046
- status = 'ok' if (errorCode == '0') else 'failed'
6047
- amountRaw = self.safe_number(entry, 'amt')
6048
- typeRaw = self.safe_string(entry, 'type')
6049
- type = 'reduce' if (typeRaw == 'reduce') else 'add'
6050
- marketId = self.safe_string(entry, 'instId')
6567
+ data = self.safe_list(response, 'data', [])
6568
+ entry = self.safe_dict(data, 0, {})
6569
+ errorCode = self.safe_string(response, 'code')
6570
+ return self.extend(self.parse_margin_modification(entry, market), {
6571
+ 'status': 'ok' if (errorCode == '0') else 'failed',
6572
+ })
6573
+
6574
+ def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
6575
+ #
6576
+ # addMargin/reduceMargin
6577
+ #
6578
+ # {
6579
+ # "amt": "0.01",
6580
+ # "instId": "ETH-USD-SWAP",
6581
+ # "posSide": "net",
6582
+ # "type": "reduce"
6583
+ # }
6584
+ #
6585
+ # fetchMarginAdjustmentHistory
6586
+ #
6587
+ # {
6588
+ # bal: '67621.4325135010619812',
6589
+ # balChg: '-10.0000000000000000',
6590
+ # billId: '691293628710342659',
6591
+ # ccy: 'USDT',
6592
+ # clOrdId: '',
6593
+ # execType: '',
6594
+ # fee: '0',
6595
+ # fillFwdPx: '',
6596
+ # fillIdxPx: '',
6597
+ # fillMarkPx: '',
6598
+ # fillMarkVol: '',
6599
+ # fillPxUsd: '',
6600
+ # fillPxVol: '',
6601
+ # fillTime: '1711089244850',
6602
+ # from: '',
6603
+ # instId: 'XRP-USDT-SWAP',
6604
+ # instType: 'SWAP',
6605
+ # interest: '0',
6606
+ # mgnMode: 'isolated',
6607
+ # notes: '',
6608
+ # ordId: '',
6609
+ # pnl: '0',
6610
+ # posBal: '73.12',
6611
+ # posBalChg: '10.00',
6612
+ # px: '',
6613
+ # subType: '160',
6614
+ # sz: '10',
6615
+ # tag: '',
6616
+ # to: '',
6617
+ # tradeId: '0',
6618
+ # ts: '1711089244699',
6619
+ # type: '6'
6620
+ # }
6621
+ #
6622
+ amountRaw = self.safe_string_2(data, 'amt', 'posBalChg')
6623
+ typeRaw = self.safe_string(data, 'type')
6624
+ type = None
6625
+ if typeRaw == '6':
6626
+ type = 'add' if Precise.string_gt(amountRaw, '0') else 'reduce'
6627
+ else:
6628
+ type = typeRaw
6629
+ amount = Precise.string_abs(amountRaw)
6630
+ marketId = self.safe_string(data, 'instId')
6051
6631
  responseMarket = self.safe_market(marketId, market)
6052
6632
  code = responseMarket['base'] if responseMarket['inverse'] else responseMarket['quote']
6633
+ timestamp = self.safe_integer(data, 'ts')
6053
6634
  return {
6054
6635
  'info': data,
6636
+ 'symbol': responseMarket['symbol'],
6055
6637
  'type': type,
6056
- 'amount': amountRaw,
6638
+ 'marginMode': 'isolated',
6639
+ 'amount': self.parse_number(amount),
6057
6640
  'code': code,
6058
- 'symbol': responseMarket['symbol'],
6059
- 'status': status,
6641
+ 'total': None,
6642
+ 'status': None,
6643
+ 'timestamp': timestamp,
6644
+ 'datetime': self.iso8601(timestamp),
6060
6645
  }
6061
6646
 
6062
- def reduce_margin(self, symbol: str, amount, params={}):
6647
+ def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
6063
6648
  """
6064
6649
  remove margin from a position
6065
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-increase-decrease-margin
6650
+
6651
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-increase-decrease-margin
6652
+
6066
6653
  :param str symbol: unified market symbol
6067
6654
  :param float amount: the amount of margin to remove
6068
6655
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -6070,10 +6657,12 @@ class okx(Exchange, ImplicitAPI):
6070
6657
  """
6071
6658
  return self.modify_margin_helper(symbol, amount, 'reduce', params)
6072
6659
 
6073
- def add_margin(self, symbol: str, amount, params={}):
6660
+ def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
6074
6661
  """
6075
6662
  add margin
6076
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-increase-decrease-margin
6663
+
6664
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-increase-decrease-margin
6665
+
6077
6666
  :param str symbol: unified market symbol
6078
6667
  :param float amount: amount of margin to add
6079
6668
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -6081,10 +6670,12 @@ class okx(Exchange, ImplicitAPI):
6081
6670
  """
6082
6671
  return self.modify_margin_helper(symbol, amount, 'add', params)
6083
6672
 
6084
- def fetch_market_leverage_tiers(self, symbol: str, params={}):
6673
+ def fetch_market_leverage_tiers(self, symbol: str, params={}) -> List[LeverageTier]:
6085
6674
  """
6086
6675
  retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes for a single market
6087
- :see: https://www.okx.com/docs-v5/en/#rest-api-public-data-get-position-tiers
6676
+
6677
+ https://www.okx.com/docs-v5/en/#rest-api-public-data-get-position-tiers
6678
+
6088
6679
  :param str symbol: unified market symbol
6089
6680
  :param dict [params]: extra parameters specific to the exchange API endpoint
6090
6681
  :param str [params.marginMode]: 'cross' or 'isolated'
@@ -6101,7 +6692,7 @@ class okx(Exchange, ImplicitAPI):
6101
6692
  marginMode, params = self.handle_margin_mode_and_params('fetchMarketLeverageTiers', params)
6102
6693
  if marginMode is None:
6103
6694
  marginMode = self.safe_string(params, 'tdMode', 'cross') # cross marginMode
6104
- request = {
6695
+ request: dict = {
6105
6696
  'instType': type,
6106
6697
  'tdMode': marginMode,
6107
6698
  'uly': uly,
@@ -6130,12 +6721,12 @@ class okx(Exchange, ImplicitAPI):
6130
6721
  # ]
6131
6722
  # }
6132
6723
  #
6133
- data = self.safe_value(response, 'data')
6724
+ data = self.safe_list(response, 'data', [])
6134
6725
  return self.parse_market_leverage_tiers(data, market)
6135
6726
 
6136
- def parse_market_leverage_tiers(self, info, market: Market = None):
6727
+ def parse_market_leverage_tiers(self, info, market: Market = None) -> List[LeverageTier]:
6137
6728
  """
6138
- * @ignore
6729
+ @ignore
6139
6730
  :param dict info: Exchange response for 1 market
6140
6731
  :param dict market: CCXT market
6141
6732
  """
@@ -6160,8 +6751,10 @@ class okx(Exchange, ImplicitAPI):
6160
6751
  tiers = []
6161
6752
  for i in range(0, len(info)):
6162
6753
  tier = info[i]
6754
+ marketId = self.safe_string(tier, 'instId')
6163
6755
  tiers.append({
6164
6756
  'tier': self.safe_integer(tier, 'tier'),
6757
+ 'symbol': self.safe_symbol(marketId, market),
6165
6758
  'currency': market['quote'],
6166
6759
  'minNotional': self.safe_number(tier, 'minSz'),
6167
6760
  'maxNotional': self.safe_number(tier, 'maxSz'),
@@ -6171,10 +6764,12 @@ class okx(Exchange, ImplicitAPI):
6171
6764
  })
6172
6765
  return tiers
6173
6766
 
6174
- def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
6767
+ def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[BorrowInterest]:
6175
6768
  """
6176
6769
  fetch the interest owed by the user for borrowing currency for margin trading
6177
- :see: https://www.okx.com/docs-v5/en/#rest-api-account-get-interest-accrued-data
6770
+
6771
+ https://www.okx.com/docs-v5/en/#rest-api-account-get-interest-accrued-data
6772
+
6178
6773
  :param str code: the unified currency code for the currency of the interest
6179
6774
  :param str symbol: the market symbol of an isolated margin market, if None, the interest for cross margin markets is returned
6180
6775
  :param int [since]: timestamp in ms of the earliest time to receive interest records for
@@ -6189,7 +6784,7 @@ class okx(Exchange, ImplicitAPI):
6189
6784
  marginMode, params = self.handle_margin_mode_and_params('fetchBorrowInterest', params)
6190
6785
  if marginMode is None:
6191
6786
  marginMode = self.safe_string(params, 'mgnMode', 'cross') # cross marginMode
6192
- request = {
6787
+ request: dict = {
6193
6788
  'mgnMode': marginMode,
6194
6789
  }
6195
6790
  market = None
@@ -6223,31 +6818,33 @@ class okx(Exchange, ImplicitAPI):
6223
6818
  # "msg": ""
6224
6819
  # }
6225
6820
  #
6226
- data = self.safe_value(response, 'data')
6821
+ data = self.safe_list(response, 'data', [])
6227
6822
  interest = self.parse_borrow_interests(data)
6228
6823
  return self.filter_by_currency_since_limit(interest, code, since, limit)
6229
6824
 
6230
- def parse_borrow_interest(self, info, market: Market = None):
6825
+ def parse_borrow_interest(self, info: dict, market: Market = None) -> BorrowInterest:
6231
6826
  instId = self.safe_string(info, 'instId')
6232
6827
  if instId is not None:
6233
6828
  market = self.safe_market(instId, market)
6234
6829
  timestamp = self.safe_integer(info, 'ts')
6235
6830
  return {
6831
+ 'info': info,
6236
6832
  'symbol': self.safe_string(market, 'symbol'),
6237
- 'marginMode': self.safe_string(info, 'mgnMode'),
6238
6833
  'currency': self.safe_currency_code(self.safe_string(info, 'ccy')),
6239
6834
  'interest': self.safe_number(info, 'interest'),
6240
6835
  'interestRate': self.safe_number(info, 'interestRate'),
6241
6836
  'amountBorrowed': self.safe_number(info, 'liab'),
6837
+ 'marginMode': self.safe_string(info, 'mgnMode'),
6242
6838
  'timestamp': timestamp, # Interest accrued time
6243
6839
  'datetime': self.iso8601(timestamp),
6244
- 'info': info,
6245
6840
  }
6246
6841
 
6247
6842
  def borrow_cross_margin(self, code: str, amount: float, params={}):
6248
6843
  """
6249
6844
  create a loan to borrow margin(need to be VIP 5 and above)
6250
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-vip-loans-borrow-and-repay
6845
+
6846
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-vip-loans-borrow-and-repay
6847
+
6251
6848
  :param str code: unified currency code of the currency to borrow
6252
6849
  :param float amount: the amount to borrow
6253
6850
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -6255,7 +6852,7 @@ class okx(Exchange, ImplicitAPI):
6255
6852
  """
6256
6853
  self.load_markets()
6257
6854
  currency = self.currency(code)
6258
- request = {
6855
+ request: dict = {
6259
6856
  'ccy': currency['id'],
6260
6857
  'amt': self.currency_to_precision(code, amount),
6261
6858
  'side': 'borrow',
@@ -6276,14 +6873,16 @@ class okx(Exchange, ImplicitAPI):
6276
6873
  # "msg": ""
6277
6874
  # }
6278
6875
  #
6279
- data = self.safe_value(response, 'data', [])
6280
- loan = self.safe_value(data, 0)
6876
+ data = self.safe_list(response, 'data', [])
6877
+ loan = self.safe_dict(data, 0, {})
6281
6878
  return self.parse_margin_loan(loan, currency)
6282
6879
 
6283
6880
  def repay_cross_margin(self, code: str, amount, params={}):
6284
6881
  """
6285
6882
  repay borrowed margin and interest
6286
- :see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-vip-loans-borrow-and-repay
6883
+
6884
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-vip-loans-borrow-and-repay
6885
+
6287
6886
  :param str code: unified currency code of the currency to repay
6288
6887
  :param float amount: the amount to repay
6289
6888
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -6296,7 +6895,7 @@ class okx(Exchange, ImplicitAPI):
6296
6895
  if id is None:
6297
6896
  raise ArgumentsRequired(self.id + ' repayCrossMargin() requires an id parameter')
6298
6897
  currency = self.currency(code)
6299
- request = {
6898
+ request: dict = {
6300
6899
  'ccy': currency['id'],
6301
6900
  'amt': self.currency_to_precision(code, amount),
6302
6901
  'side': 'repay',
@@ -6318,8 +6917,8 @@ class okx(Exchange, ImplicitAPI):
6318
6917
  # "msg": ""
6319
6918
  # }
6320
6919
  #
6321
- data = self.safe_value(response, 'data', [])
6322
- loan = self.safe_value(data, 0)
6920
+ data = self.safe_list(response, 'data', [])
6921
+ loan = self.safe_dict(data, 0, {})
6323
6922
  return self.parse_margin_loan(loan, currency)
6324
6923
 
6325
6924
  def parse_margin_loan(self, info, currency: Currency = None):
@@ -6348,7 +6947,9 @@ class okx(Exchange, ImplicitAPI):
6348
6947
  def fetch_open_interest(self, symbol: str, params={}):
6349
6948
  """
6350
6949
  Retrieves the open interest of a currency
6351
- :see: https://www.okx.com/docs-v5/en/#rest-api-public-data-get-open-interest
6950
+
6951
+ https://www.okx.com/docs-v5/en/#rest-api-public-data-get-open-interest
6952
+
6352
6953
  :param str symbol: Unified CCXT market symbol
6353
6954
  :param dict [params]: exchange specific parameters
6354
6955
  :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
@@ -6359,7 +6960,7 @@ class okx(Exchange, ImplicitAPI):
6359
6960
  raise BadRequest(self.id + ' fetchOpenInterest() supports contract markets only')
6360
6961
  type = self.convert_to_instrument_type(market['type'])
6361
6962
  uly = self.safe_string(market['info'], 'uly')
6362
- request = {
6963
+ request: dict = {
6363
6964
  'instType': type,
6364
6965
  'uly': uly,
6365
6966
  'instId': market['id'],
@@ -6380,14 +6981,16 @@ class okx(Exchange, ImplicitAPI):
6380
6981
  # "msg": ""
6381
6982
  # }
6382
6983
  #
6383
- data = self.safe_value(response, 'data', [])
6984
+ data = self.safe_list(response, 'data', [])
6384
6985
  return self.parse_open_interest(data[0], market)
6385
6986
 
6386
6987
  def fetch_open_interest_history(self, symbol: str, timeframe='1d', since: Int = None, limit: Int = None, params={}):
6387
6988
  """
6388
6989
  Retrieves the open interest history of a currency
6389
- :see: https://www.okx.com/docs-v5/en/#rest-api-trading-data-get-contracts-open-interest-and-volume
6390
- :see: https://www.okx.com/docs-v5/en/#rest-api-trading-data-get-options-open-interest-and-volume
6990
+
6991
+ https://www.okx.com/docs-v5/en/#rest-api-trading-data-get-contracts-open-interest-and-volume
6992
+ https://www.okx.com/docs-v5/en/#rest-api-trading-data-get-options-open-interest-and-volume
6993
+
6391
6994
  :param str symbol: Unified CCXT currency code or unified symbol
6392
6995
  :param str timeframe: "5m", "1h", or "1d" for option only "1d" or "8h"
6393
6996
  :param int [since]: The time in ms of the earliest record to retrieve unix timestamp
@@ -6396,8 +6999,8 @@ class okx(Exchange, ImplicitAPI):
6396
6999
  :param int [params.until]: The time in ms of the latest record to retrieve unix timestamp
6397
7000
  :returns: An array of `open interest structures <https://docs.ccxt.com/#/?id=open-interest-structure>`
6398
7001
  """
6399
- options = self.safe_value(self.options, 'fetchOpenInterestHistory', {})
6400
- timeframes = self.safe_value(options, 'timeframes', {})
7002
+ options = self.safe_dict(self.options, 'fetchOpenInterestHistory', {})
7003
+ timeframes = self.safe_dict(options, 'timeframes', {})
6401
7004
  timeframe = self.safe_string(timeframes, timeframe, timeframe)
6402
7005
  if timeframe != '5m' and timeframe != '1H' and timeframe != '1D':
6403
7006
  raise BadRequest(self.id + ' fetchOpenInterestHistory cannot only use the 5m, 1h, and 1d timeframe')
@@ -6411,7 +7014,7 @@ class okx(Exchange, ImplicitAPI):
6411
7014
  else:
6412
7015
  currency = self.currency(symbol)
6413
7016
  currencyId = currency['id']
6414
- request = {
7017
+ request: dict = {
6415
7018
  'ccy': currencyId,
6416
7019
  'period': timeframe,
6417
7020
  }
@@ -6423,10 +7026,10 @@ class okx(Exchange, ImplicitAPI):
6423
7026
  else:
6424
7027
  if since is not None:
6425
7028
  request['begin'] = since
6426
- until = self.safe_integer_2(params, 'till', 'until')
7029
+ until = self.safe_integer(params, 'until')
6427
7030
  if until is not None:
6428
7031
  request['end'] = until
6429
- params = self.omit(params, ['until', 'till'])
7032
+ params = self.omit(params, ['until'])
6430
7033
  response = self.publicGetRubikStatContractsOpenInterestVolume(self.extend(request, params))
6431
7034
  #
6432
7035
  # {
@@ -6442,8 +7045,8 @@ class okx(Exchange, ImplicitAPI):
6442
7045
  # "msg": ''
6443
7046
  # }
6444
7047
  #
6445
- data = self.safe_value(response, 'data', [])
6446
- return self.parse_open_interests(data, None, since, limit)
7048
+ data = self.safe_list(response, 'data', [])
7049
+ return self.parse_open_interests_history(data, None, since, limit)
6447
7050
 
6448
7051
  def parse_open_interest(self, interest, market: Market = None):
6449
7052
  #
@@ -6462,6 +7065,7 @@ class okx(Exchange, ImplicitAPI):
6462
7065
  # "instType": "OPTION",
6463
7066
  # "oi": "300",
6464
7067
  # "oiCcy": "3",
7068
+ # "oiUsd": "3",
6465
7069
  # "ts": "1684551166251"
6466
7070
  # }
6467
7071
  #
@@ -6484,7 +7088,7 @@ class okx(Exchange, ImplicitAPI):
6484
7088
  else:
6485
7089
  baseVolume = self.safe_number(interest, 'oiCcy')
6486
7090
  openInterestAmount = self.safe_number(interest, 'oi')
6487
- openInterestValue = self.safe_number(interest, 'oiCcy')
7091
+ openInterestValue = self.safe_number(interest, 'oiUsd')
6488
7092
  return self.safe_open_interest({
6489
7093
  'symbol': self.safe_symbol(id),
6490
7094
  'baseVolume': baseVolume, # deprecated
@@ -6507,13 +7111,19 @@ class okx(Exchange, ImplicitAPI):
6507
7111
  def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
6508
7112
  """
6509
7113
  fetch deposit and withdraw fees
6510
- :see: https://www.okx.com/docs-v5/en/#rest-api-funding-get-currencies
7114
+
7115
+ https://www.okx.com/docs-v5/en/#rest-api-funding-get-currencies
7116
+
6511
7117
  :param str[]|None codes: list of unified currency codes
6512
7118
  :param dict [params]: extra parameters specific to the exchange API endpoint
6513
7119
  :returns dict[]: a list of `fees structures <https://docs.ccxt.com/#/?id=fee-structure>`
6514
7120
  """
6515
7121
  self.load_markets()
6516
- response = self.privateGetAssetCurrencies(params)
7122
+ request = {}
7123
+ if codes is not None:
7124
+ ids = self.currency_ids(codes)
7125
+ request['ccy'] = ','.join(ids)
7126
+ response = self.privateGetAssetCurrencies(self.extend(request, params))
6517
7127
  #
6518
7128
  # {
6519
7129
  # "code": "0",
@@ -6557,7 +7167,7 @@ class okx(Exchange, ImplicitAPI):
6557
7167
  # "msg": ""
6558
7168
  # }
6559
7169
  #
6560
- data = self.safe_value(response, 'data')
7170
+ data = self.safe_list(response, 'data')
6561
7171
  return self.parse_deposit_withdraw_fees(data, codes)
6562
7172
 
6563
7173
  def parse_deposit_withdraw_fees(self, response, codes=None, currencyIdKey=None):
@@ -6582,7 +7192,7 @@ class okx(Exchange, ImplicitAPI):
6582
7192
  # }
6583
7193
  # ]
6584
7194
  #
6585
- depositWithdrawFees = {}
7195
+ depositWithdrawFees: dict = {}
6586
7196
  codes = self.market_codes(codes)
6587
7197
  for i in range(0, len(response)):
6588
7198
  feeInfo = response[i]
@@ -6594,14 +7204,16 @@ class okx(Exchange, ImplicitAPI):
6594
7204
  depositWithdrawFees[code] = self.deposit_withdraw_fee({})
6595
7205
  depositWithdrawFees[code]['info'][currencyId] = feeInfo
6596
7206
  chain = self.safe_string(feeInfo, 'chain')
7207
+ if chain is None:
7208
+ continue
6597
7209
  chainSplit = chain.split('-')
6598
7210
  networkId = self.safe_value(chainSplit, 1)
6599
- withdrawFee = self.safe_number(feeInfo, 'minFee')
6600
- withdrawResult = {
7211
+ withdrawFee = self.safe_number(feeInfo, 'fee')
7212
+ withdrawResult: dict = {
6601
7213
  'fee': withdrawFee,
6602
7214
  'percentage': False if (withdrawFee is not None) else None,
6603
7215
  }
6604
- depositResult = {
7216
+ depositResult: dict = {
6605
7217
  'fee': None,
6606
7218
  'percentage': None,
6607
7219
  }
@@ -6620,7 +7232,9 @@ class okx(Exchange, ImplicitAPI):
6620
7232
  def fetch_settlement_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
6621
7233
  """
6622
7234
  fetches historical settlement records
6623
- :see: https://www.okx.com/docs-v5/en/#rest-api-public-data-get-delivery-exercise-history
7235
+
7236
+ https://www.okx.com/docs-v5/en/#rest-api-public-data-get-delivery-exercise-history
7237
+
6624
7238
  :param str symbol: unified market symbol to fetch the settlement history for
6625
7239
  :param int [since]: timestamp in ms
6626
7240
  :param int [limit]: number of records
@@ -6635,7 +7249,7 @@ class okx(Exchange, ImplicitAPI):
6635
7249
  type, params = self.handle_market_type_and_params('fetchSettlementHistory', market, params)
6636
7250
  if type != 'future' and type != 'option':
6637
7251
  raise NotSupported(self.id + ' fetchSettlementHistory() supports futures and options markets only')
6638
- request = {
7252
+ request: dict = {
6639
7253
  'instType': self.convert_to_instrument_type(type),
6640
7254
  'uly': market['baseId'] + '-' + market['quoteId'],
6641
7255
  }
@@ -6662,7 +7276,7 @@ class okx(Exchange, ImplicitAPI):
6662
7276
  # "msg": ""
6663
7277
  # }
6664
7278
  #
6665
- data = self.safe_value(response, 'data', [])
7279
+ data = self.safe_list(response, 'data', [])
6666
7280
  settlements = self.parse_settlements(data, market)
6667
7281
  sorted = self.sort_by(settlements, 'timestamp')
6668
7282
  return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
@@ -6701,7 +7315,7 @@ class okx(Exchange, ImplicitAPI):
6701
7315
  for i in range(0, len(settlements)):
6702
7316
  entry = settlements[i]
6703
7317
  timestamp = self.safe_integer(entry, 'ts')
6704
- details = self.safe_value(entry, 'details', [])
7318
+ details = self.safe_list(entry, 'details', [])
6705
7319
  for j in range(0, len(details)):
6706
7320
  settlement = self.parse_settlement(details[j], market)
6707
7321
  result.append(self.extend(settlement, {
@@ -6713,7 +7327,9 @@ class okx(Exchange, ImplicitAPI):
6713
7327
  def fetch_underlying_assets(self, params={}):
6714
7328
  """
6715
7329
  fetches the market ids of underlying assets for a specific contract market type
6716
- :see: https://www.okx.com/docs-v5/en/#public-data-rest-api-get-underlying
7330
+
7331
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-underlying
7332
+
6717
7333
  :param dict [params]: exchange specific params
6718
7334
  :param str [params.type]: the contract market type, 'option', 'swap' or 'future', the default is 'option'
6719
7335
  :returns dict[]: a list of `underlying assets <https://docs.ccxt.com/#/?id=underlying-assets-structure>`
@@ -6725,7 +7341,7 @@ class okx(Exchange, ImplicitAPI):
6725
7341
  marketType = 'option'
6726
7342
  if (marketType != 'option') and (marketType != 'swap') and (marketType != 'future'):
6727
7343
  raise NotSupported(self.id + ' fetchUnderlyingAssets() supports contract markets only')
6728
- request = {
7344
+ request: dict = {
6729
7345
  'instType': self.convert_to_instrument_type(marketType),
6730
7346
  }
6731
7347
  response = self.publicGetPublicUnderlying(self.extend(request, params))
@@ -6741,13 +7357,15 @@ class okx(Exchange, ImplicitAPI):
6741
7357
  # "msg": ""
6742
7358
  # }
6743
7359
  #
6744
- underlyings = self.safe_value(response, 'data', [])
7360
+ underlyings = self.safe_list(response, 'data', [])
6745
7361
  return underlyings[0]
6746
7362
 
6747
7363
  def fetch_greeks(self, symbol: str, params={}) -> Greeks:
6748
7364
  """
6749
7365
  fetches an option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
6750
- :see: https://www.okx.com/docs-v5/en/#public-data-rest-api-get-option-market-data
7366
+
7367
+ https://www.okx.com/docs-v5/en/#public-data-rest-api-get-option-market-data
7368
+
6751
7369
  :param str symbol: unified symbol of the market to fetch greeks for
6752
7370
  :param dict [params]: extra parameters specific to the exchange API endpoint
6753
7371
  :returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
@@ -6756,7 +7374,7 @@ class okx(Exchange, ImplicitAPI):
6756
7374
  market = self.market(symbol)
6757
7375
  marketId = market['id']
6758
7376
  optionParts = marketId.split('-')
6759
- request = {
7377
+ request: dict = {
6760
7378
  'uly': market['info']['uly'],
6761
7379
  'instFamily': market['info']['instFamily'],
6762
7380
  'expTime': self.safe_string(optionParts, 2),
@@ -6791,7 +7409,7 @@ class okx(Exchange, ImplicitAPI):
6791
7409
  # "msg": ""
6792
7410
  # }
6793
7411
  #
6794
- data = self.safe_value(response, 'data', [])
7412
+ data = self.safe_list(response, 'data', [])
6795
7413
  for i in range(0, len(data)):
6796
7414
  entry = data[i]
6797
7415
  entryMarketId = self.safe_string(entry, 'instId')
@@ -6799,7 +7417,7 @@ class okx(Exchange, ImplicitAPI):
6799
7417
  return self.parse_greeks(entry, market)
6800
7418
  return None
6801
7419
 
6802
- def parse_greeks(self, greeks, market: Market = None):
7420
+ def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
6803
7421
  #
6804
7422
  # {
6805
7423
  # "askVol": "0",
@@ -6851,15 +7469,17 @@ class okx(Exchange, ImplicitAPI):
6851
7469
  def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
6852
7470
  """
6853
7471
  closes open positions for a market
6854
- :see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-close-positions
7472
+
7473
+ https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-close-positions
7474
+
6855
7475
  :param str symbol: Unified CCXT market symbol
6856
7476
  :param str [side]: 'buy' or 'sell', leave in net mode
6857
7477
  :param dict [params]: extra parameters specific to the okx api endpoint
6858
7478
  :param str [params.clientOrderId]: a unique identifier for the order
6859
7479
  :param str [params.marginMode]: 'cross' or 'isolated', default is 'cross
6860
7480
  :param str [params.code]: *required in the case of closing cross MARGIN position for Single-currency margin* margin currency
6861
- *
6862
- * EXCHANGE SPECIFIC PARAMETERS
7481
+
7482
+ EXCHANGE SPECIFIC PARAMETERS
6863
7483
  :param boolean [params.autoCxl]: whether any pending orders for closing out needs to be automatically canceled when close position via a market order. False or True, the default is False
6864
7484
  :param str [params.tag]: order tag a combination of case-sensitive alphanumerics, all numbers, or all letters of up to 16 characters
6865
7485
  :returns dict[]: `A list of position structures <https://docs.ccxt.com/#/?id=position-structure>`
@@ -6870,7 +7490,7 @@ class okx(Exchange, ImplicitAPI):
6870
7490
  code = self.safe_string(params, 'code')
6871
7491
  marginMode = None
6872
7492
  marginMode, params = self.handle_margin_mode_and_params('closePosition', params, 'cross')
6873
- request = {
7493
+ request: dict = {
6874
7494
  'instId': market['id'],
6875
7495
  'mgnMode': marginMode,
6876
7496
  }
@@ -6904,11 +7524,478 @@ class okx(Exchange, ImplicitAPI):
6904
7524
  # "outTime": "1701877077102579"
6905
7525
  # }
6906
7526
  #
6907
- data = self.safe_value(response, 'data')
6908
- order = self.safe_value(data, 0)
7527
+ data = self.safe_list(response, 'data', [])
7528
+ order = self.safe_dict(data, 0)
6909
7529
  return self.parse_order(order, market)
6910
7530
 
6911
- def handle_errors(self, httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody):
7531
+ def fetch_option(self, symbol: str, params={}) -> Option:
7532
+ """
7533
+ fetches option data that is commonly found in an option chain
7534
+
7535
+ https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-ticker
7536
+
7537
+ :param str symbol: unified market symbol
7538
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7539
+ :returns dict: an `option chain structure <https://docs.ccxt.com/#/?id=option-chain-structure>`
7540
+ """
7541
+ self.load_markets()
7542
+ market = self.market(symbol)
7543
+ request: dict = {
7544
+ 'instId': market['id'],
7545
+ }
7546
+ response = self.publicGetMarketTicker(self.extend(request, params))
7547
+ #
7548
+ # {
7549
+ # "code": "0",
7550
+ # "msg": "",
7551
+ # "data": [
7552
+ # {
7553
+ # "instType": "OPTION",
7554
+ # "instId": "BTC-USD-241227-60000-P",
7555
+ # "last": "",
7556
+ # "lastSz": "0",
7557
+ # "askPx": "",
7558
+ # "askSz": "0",
7559
+ # "bidPx": "",
7560
+ # "bidSz": "0",
7561
+ # "open24h": "",
7562
+ # "high24h": "",
7563
+ # "low24h": "",
7564
+ # "volCcy24h": "0",
7565
+ # "vol24h": "0",
7566
+ # "ts": "1711176035035",
7567
+ # "sodUtc0": "",
7568
+ # "sodUtc8": ""
7569
+ # }
7570
+ # ]
7571
+ # }
7572
+ #
7573
+ result = self.safe_list(response, 'data', [])
7574
+ chain = self.safe_dict(result, 0, {})
7575
+ return self.parse_option(chain, None, market)
7576
+
7577
+ def fetch_option_chain(self, code: str, params={}) -> OptionChain:
7578
+ """
7579
+ fetches data for an underlying asset that is commonly found in an option chain
7580
+
7581
+ https://www.okx.com/docs-v5/en/#order-book-trading-market-data-get-tickers
7582
+
7583
+ :param str code: base currency to fetch an option chain for
7584
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7585
+ :param str [params.uly]: the underlying asset, can be obtained from fetchUnderlyingAssets()
7586
+ :returns dict: a list of `option chain structures <https://docs.ccxt.com/#/?id=option-chain-structure>`
7587
+ """
7588
+ self.load_markets()
7589
+ currency = self.currency(code)
7590
+ request: dict = {
7591
+ 'uly': currency['code'] + '-USD',
7592
+ 'instType': 'OPTION',
7593
+ }
7594
+ response = self.publicGetMarketTickers(self.extend(request, params))
7595
+ #
7596
+ # {
7597
+ # "code": "0",
7598
+ # "msg": "",
7599
+ # "data": [
7600
+ # {
7601
+ # "instType": "OPTION",
7602
+ # "instId": "BTC-USD-240323-52000-C",
7603
+ # "last": "",
7604
+ # "lastSz": "0",
7605
+ # "askPx": "",
7606
+ # "askSz": "0",
7607
+ # "bidPx": "",
7608
+ # "bidSz": "0",
7609
+ # "open24h": "",
7610
+ # "high24h": "",
7611
+ # "low24h": "",
7612
+ # "volCcy24h": "0",
7613
+ # "vol24h": "0",
7614
+ # "ts": "1711176207008",
7615
+ # "sodUtc0": "",
7616
+ # "sodUtc8": ""
7617
+ # },
7618
+ # ]
7619
+ # }
7620
+ #
7621
+ result = self.safe_list(response, 'data', [])
7622
+ return self.parse_option_chain(result, None, 'instId')
7623
+
7624
+ def parse_option(self, chain: dict, currency: Currency = None, market: Market = None) -> Option:
7625
+ #
7626
+ # {
7627
+ # "instType": "OPTION",
7628
+ # "instId": "BTC-USD-241227-60000-P",
7629
+ # "last": "",
7630
+ # "lastSz": "0",
7631
+ # "askPx": "",
7632
+ # "askSz": "0",
7633
+ # "bidPx": "",
7634
+ # "bidSz": "0",
7635
+ # "open24h": "",
7636
+ # "high24h": "",
7637
+ # "low24h": "",
7638
+ # "volCcy24h": "0",
7639
+ # "vol24h": "0",
7640
+ # "ts": "1711176035035",
7641
+ # "sodUtc0": "",
7642
+ # "sodUtc8": ""
7643
+ # }
7644
+ #
7645
+ marketId = self.safe_string(chain, 'instId')
7646
+ market = self.safe_market(marketId, market)
7647
+ timestamp = self.safe_integer(chain, 'ts')
7648
+ return {
7649
+ 'info': chain,
7650
+ 'currency': None,
7651
+ 'symbol': market['symbol'],
7652
+ 'timestamp': timestamp,
7653
+ 'datetime': self.iso8601(timestamp),
7654
+ 'impliedVolatility': None,
7655
+ 'openInterest': None,
7656
+ 'bidPrice': self.safe_number(chain, 'bidPx'),
7657
+ 'askPrice': self.safe_number(chain, 'askPx'),
7658
+ 'midPrice': None,
7659
+ 'markPrice': None,
7660
+ 'lastPrice': self.safe_number(chain, 'last'),
7661
+ 'underlyingPrice': None,
7662
+ 'change': None,
7663
+ 'percentage': None,
7664
+ 'baseVolume': self.safe_number(chain, 'volCcy24h'),
7665
+ 'quoteVolume': None,
7666
+ }
7667
+
7668
+ def fetch_convert_quote(self, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
7669
+ """
7670
+ fetch a quote for converting from one currency to another
7671
+
7672
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-estimate-quote
7673
+
7674
+ :param str fromCode: the currency that you want to sell and convert from
7675
+ :param str toCode: the currency that you want to buy and convert into
7676
+ :param float [amount]: how much you want to trade in units of the from currency
7677
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7678
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
7679
+ """
7680
+ self.load_markets()
7681
+ request: dict = {
7682
+ 'baseCcy': fromCode.upper(),
7683
+ 'quoteCcy': toCode.upper(),
7684
+ 'rfqSzCcy': fromCode.upper(),
7685
+ 'rfqSz': self.number_to_string(amount),
7686
+ 'side': 'sell',
7687
+ }
7688
+ response = self.privatePostAssetConvertEstimateQuote(self.extend(request, params))
7689
+ #
7690
+ # {
7691
+ # "code": "0",
7692
+ # "data": [
7693
+ # {
7694
+ # "baseCcy": "ETH",
7695
+ # "baseSz": "0.01023052",
7696
+ # "clQReqId": "",
7697
+ # "cnvtPx": "2932.40104429",
7698
+ # "origRfqSz": "30",
7699
+ # "quoteCcy": "USDT",
7700
+ # "quoteId": "quoterETH-USDT16461885104612381",
7701
+ # "quoteSz": "30",
7702
+ # "quoteTime": "1646188510461",
7703
+ # "rfqSz": "30",
7704
+ # "rfqSzCcy": "USDT",
7705
+ # "side": "buy",
7706
+ # "ttlMs": "10000"
7707
+ # }
7708
+ # ],
7709
+ # "msg": ""
7710
+ # }
7711
+ #
7712
+ data = self.safe_list(response, 'data', [])
7713
+ result = self.safe_dict(data, 0, {})
7714
+ fromCurrencyId = self.safe_string(result, 'baseCcy', fromCode)
7715
+ fromCurrency = self.currency(fromCurrencyId)
7716
+ toCurrencyId = self.safe_string(result, 'quoteCcy', toCode)
7717
+ toCurrency = self.currency(toCurrencyId)
7718
+ return self.parse_conversion(result, fromCurrency, toCurrency)
7719
+
7720
+ def create_convert_trade(self, id: str, fromCode: str, toCode: str, amount: Num = None, params={}) -> Conversion:
7721
+ """
7722
+ convert from one currency to another
7723
+
7724
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-convert-trade
7725
+
7726
+ :param str id: the id of the trade that you want to make
7727
+ :param str fromCode: the currency that you want to sell and convert from
7728
+ :param str toCode: the currency that you want to buy and convert into
7729
+ :param float [amount]: how much you want to trade in units of the from currency
7730
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7731
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
7732
+ """
7733
+ self.load_markets()
7734
+ request: dict = {
7735
+ 'quoteId': id,
7736
+ 'baseCcy': fromCode,
7737
+ 'quoteCcy': toCode,
7738
+ 'szCcy': fromCode,
7739
+ 'sz': self.number_to_string(amount),
7740
+ 'side': 'sell',
7741
+ }
7742
+ response = self.privatePostAssetConvertTrade(self.extend(request, params))
7743
+ #
7744
+ # {
7745
+ # "code": "0",
7746
+ # "data": [
7747
+ # {
7748
+ # "baseCcy": "ETH",
7749
+ # "clTReqId": "",
7750
+ # "fillBaseSz": "0.01023052",
7751
+ # "fillPx": "2932.40104429",
7752
+ # "fillQuoteSz": "30",
7753
+ # "instId": "ETH-USDT",
7754
+ # "quoteCcy": "USDT",
7755
+ # "quoteId": "quoterETH-USDT16461885104612381",
7756
+ # "side": "buy",
7757
+ # "state": "fullyFilled",
7758
+ # "tradeId": "trader16461885203381437",
7759
+ # "ts": "1646188520338"
7760
+ # }
7761
+ # ],
7762
+ # "msg": ""
7763
+ # }
7764
+ #
7765
+ data = self.safe_list(response, 'data', [])
7766
+ result = self.safe_dict(data, 0, {})
7767
+ fromCurrencyId = self.safe_string(result, 'baseCcy', fromCode)
7768
+ fromCurrency = self.currency(fromCurrencyId)
7769
+ toCurrencyId = self.safe_string(result, 'quoteCcy', toCode)
7770
+ toCurrency = self.currency(toCurrencyId)
7771
+ return self.parse_conversion(result, fromCurrency, toCurrency)
7772
+
7773
+ def fetch_convert_trade(self, id: str, code: Str = None, params={}) -> Conversion:
7774
+ """
7775
+ fetch the data for a conversion trade
7776
+
7777
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-convert-history
7778
+
7779
+ :param str id: the id of the trade that you want to fetch
7780
+ :param str [code]: the unified currency code of the conversion trade
7781
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7782
+ :returns dict: a `conversion structure <https://docs.ccxt.com/#/?id=conversion-structure>`
7783
+ """
7784
+ self.load_markets()
7785
+ request: dict = {
7786
+ 'clTReqId': id,
7787
+ }
7788
+ response = self.privateGetAssetConvertHistory(self.extend(request, params))
7789
+ #
7790
+ # {
7791
+ # "code": "0",
7792
+ # "data": [
7793
+ # {
7794
+ # "clTReqId": "",
7795
+ # "instId": "ETH-USDT",
7796
+ # "side": "buy",
7797
+ # "fillPx": "2932.401044",
7798
+ # "baseCcy": "ETH",
7799
+ # "quoteCcy": "USDT",
7800
+ # "fillBaseSz": "0.01023052",
7801
+ # "state": "fullyFilled",
7802
+ # "tradeId": "trader16461885203381437",
7803
+ # "fillQuoteSz": "30",
7804
+ # "ts": "1646188520000"
7805
+ # }
7806
+ # ],
7807
+ # "msg": ""
7808
+ # }
7809
+ #
7810
+ data = self.safe_list(response, 'data', [])
7811
+ result = self.safe_dict(data, 0, {})
7812
+ fromCurrencyId = self.safe_string(result, 'baseCcy')
7813
+ toCurrencyId = self.safe_string(result, 'quoteCcy')
7814
+ fromCurrency = None
7815
+ toCurrency = None
7816
+ if fromCurrencyId is not None:
7817
+ fromCurrency = self.currency(fromCurrencyId)
7818
+ if toCurrencyId is not None:
7819
+ toCurrency = self.currency(toCurrencyId)
7820
+ return self.parse_conversion(result, fromCurrency, toCurrency)
7821
+
7822
+ def fetch_convert_trade_history(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Conversion]:
7823
+ """
7824
+ fetch the users history of conversion trades
7825
+
7826
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-convert-history
7827
+
7828
+ :param str [code]: the unified currency code
7829
+ :param int [since]: the earliest time in ms to fetch conversions for
7830
+ :param int [limit]: the maximum number of conversion structures to retrieve
7831
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7832
+ :param int [params.until]: timestamp in ms of the latest conversion to fetch
7833
+ :returns dict[]: a list of `conversion structures <https://docs.ccxt.com/#/?id=conversion-structure>`
7834
+ """
7835
+ self.load_markets()
7836
+ request: dict = {}
7837
+ request, params = self.handle_until_option('after', request, params)
7838
+ if since is not None:
7839
+ request['before'] = since
7840
+ if limit is not None:
7841
+ request['limit'] = limit
7842
+ response = self.privateGetAssetConvertHistory(self.extend(request, params))
7843
+ #
7844
+ # {
7845
+ # "code": "0",
7846
+ # "data": [
7847
+ # {
7848
+ # "clTReqId": "",
7849
+ # "instId": "ETH-USDT",
7850
+ # "side": "buy",
7851
+ # "fillPx": "2932.401044",
7852
+ # "baseCcy": "ETH",
7853
+ # "quoteCcy": "USDT",
7854
+ # "fillBaseSz": "0.01023052",
7855
+ # "state": "fullyFilled",
7856
+ # "tradeId": "trader16461885203381437",
7857
+ # "fillQuoteSz": "30",
7858
+ # "ts": "1646188520000"
7859
+ # }
7860
+ # ],
7861
+ # "msg": ""
7862
+ # }
7863
+ #
7864
+ rows = self.safe_list(response, 'data', [])
7865
+ return self.parse_conversions(rows, code, 'baseCcy', 'quoteCcy', since, limit)
7866
+
7867
+ def parse_conversion(self, conversion: dict, fromCurrency: Currency = None, toCurrency: Currency = None) -> Conversion:
7868
+ #
7869
+ # fetchConvertQuote
7870
+ #
7871
+ # {
7872
+ # "baseCcy": "ETH",
7873
+ # "baseSz": "0.01023052",
7874
+ # "clQReqId": "",
7875
+ # "cnvtPx": "2932.40104429",
7876
+ # "origRfqSz": "30",
7877
+ # "quoteCcy": "USDT",
7878
+ # "quoteId": "quoterETH-USDT16461885104612381",
7879
+ # "quoteSz": "30",
7880
+ # "quoteTime": "1646188510461",
7881
+ # "rfqSz": "30",
7882
+ # "rfqSzCcy": "USDT",
7883
+ # "side": "buy",
7884
+ # "ttlMs": "10000"
7885
+ # }
7886
+ #
7887
+ # createConvertTrade
7888
+ #
7889
+ # {
7890
+ # "baseCcy": "ETH",
7891
+ # "clTReqId": "",
7892
+ # "fillBaseSz": "0.01023052",
7893
+ # "fillPx": "2932.40104429",
7894
+ # "fillQuoteSz": "30",
7895
+ # "instId": "ETH-USDT",
7896
+ # "quoteCcy": "USDT",
7897
+ # "quoteId": "quoterETH-USDT16461885104612381",
7898
+ # "side": "buy",
7899
+ # "state": "fullyFilled",
7900
+ # "tradeId": "trader16461885203381437",
7901
+ # "ts": "1646188520338"
7902
+ # }
7903
+ #
7904
+ # fetchConvertTrade, fetchConvertTradeHistory
7905
+ #
7906
+ # {
7907
+ # "clTReqId": "",
7908
+ # "instId": "ETH-USDT",
7909
+ # "side": "buy",
7910
+ # "fillPx": "2932.401044",
7911
+ # "baseCcy": "ETH",
7912
+ # "quoteCcy": "USDT",
7913
+ # "fillBaseSz": "0.01023052",
7914
+ # "state": "fullyFilled",
7915
+ # "tradeId": "trader16461885203381437",
7916
+ # "fillQuoteSz": "30",
7917
+ # "ts": "1646188520000"
7918
+ # }
7919
+ #
7920
+ timestamp = self.safe_integer_2(conversion, 'quoteTime', 'ts')
7921
+ fromCoin = self.safe_string(conversion, 'baseCcy')
7922
+ fromCode = self.safe_currency_code(fromCoin, fromCurrency)
7923
+ to = self.safe_string(conversion, 'quoteCcy')
7924
+ toCode = self.safe_currency_code(to, toCurrency)
7925
+ return {
7926
+ 'info': conversion,
7927
+ 'timestamp': timestamp,
7928
+ 'datetime': self.iso8601(timestamp),
7929
+ 'id': self.safe_string_n(conversion, ['clQReqId', 'tradeId', 'quoteId']),
7930
+ 'fromCurrency': fromCode,
7931
+ 'fromAmount': self.safe_number_2(conversion, 'baseSz', 'fillBaseSz'),
7932
+ 'toCurrency': toCode,
7933
+ 'toAmount': self.safe_number_2(conversion, 'quoteSz', 'fillQuoteSz'),
7934
+ 'price': self.safe_number_2(conversion, 'cnvtPx', 'fillPx'),
7935
+ 'fee': None,
7936
+ }
7937
+
7938
+ def fetch_convert_currencies(self, params={}) -> Currencies:
7939
+ """
7940
+ fetches all available currencies that can be converted
7941
+
7942
+ https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-convert-currencies
7943
+
7944
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7945
+ :returns dict: an associative dictionary of currencies
7946
+ """
7947
+ self.load_markets()
7948
+ response = self.privateGetAssetConvertCurrencies(params)
7949
+ #
7950
+ # {
7951
+ # "code": "0",
7952
+ # "data": [
7953
+ # {
7954
+ # "ccy": "BTC",
7955
+ # "max": "",
7956
+ # "min": ""
7957
+ # },
7958
+ # ],
7959
+ # "msg": ""
7960
+ # }
7961
+ #
7962
+ result: dict = {}
7963
+ data = self.safe_list(response, 'data', [])
7964
+ for i in range(0, len(data)):
7965
+ entry = data[i]
7966
+ id = self.safe_string(entry, 'ccy')
7967
+ code = self.safe_currency_code(id)
7968
+ result[code] = {
7969
+ 'info': entry,
7970
+ 'id': id,
7971
+ 'code': code,
7972
+ 'networks': None,
7973
+ 'type': None,
7974
+ 'name': None,
7975
+ 'active': None,
7976
+ 'deposit': None,
7977
+ 'withdraw': None,
7978
+ 'fee': None,
7979
+ 'precision': None,
7980
+ 'limits': {
7981
+ 'amount': {
7982
+ 'min': self.safe_number(entry, 'min'),
7983
+ 'max': self.safe_number(entry, 'max'),
7984
+ },
7985
+ 'withdraw': {
7986
+ 'min': None,
7987
+ 'max': None,
7988
+ },
7989
+ 'deposit': {
7990
+ 'min': None,
7991
+ 'max': None,
7992
+ },
7993
+ },
7994
+ 'created': None,
7995
+ }
7996
+ return result
7997
+
7998
+ def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
6912
7999
  if not response:
6913
8000
  return None # fallback to default error handler
6914
8001
  #
@@ -6934,7 +8021,7 @@ class okx(Exchange, ImplicitAPI):
6934
8021
  code = self.safe_string(response, 'code')
6935
8022
  if (code != '0') and (code != '2'): # 2 means that bulk operation partially succeeded
6936
8023
  feedback = self.id + ' ' + body
6937
- data = self.safe_value(response, 'data', [])
8024
+ data = self.safe_list(response, 'data', [])
6938
8025
  for i in range(0, len(data)):
6939
8026
  error = data[i]
6940
8027
  errorCode = self.safe_string(error, 'sCode')
@@ -6944,3 +8031,238 @@ class okx(Exchange, ImplicitAPI):
6944
8031
  self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
6945
8032
  raise ExchangeError(feedback) # unknown message
6946
8033
  return None
8034
+
8035
+ def fetch_margin_adjustment_history(self, symbol: Str = None, type: Str = None, since: Num = None, limit: Num = None, params={}) -> List[MarginModification]:
8036
+ """
8037
+ fetches the history of margin added or reduced from contract isolated positions
8038
+
8039
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-7-days
8040
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-3-months
8041
+
8042
+ :param str [symbol]: not used by okx fetchMarginAdjustmentHistory
8043
+ :param str [type]: "add" or "reduce"
8044
+ :param int [since]: the earliest time in ms to fetch margin adjustment history for
8045
+ :param int [limit]: the maximum number of entries to retrieve
8046
+ :param dict params: extra parameters specific to the exchange api endpoint
8047
+ :param boolean [params.auto]: True if fetching auto margin increases
8048
+ :returns dict[]: a list of `margin structures <https://docs.ccxt.com/#/?id=margin-loan-structure>`
8049
+ """
8050
+ self.load_markets()
8051
+ auto = self.safe_bool(params, 'auto')
8052
+ if type is None:
8053
+ raise ArgumentsRequired(self.id + ' fetchMarginAdjustmentHistory() requires a type argument')
8054
+ isAdd = type == 'add'
8055
+ subType = '160' if isAdd else '161'
8056
+ if auto:
8057
+ if isAdd:
8058
+ subType = '162'
8059
+ else:
8060
+ raise BadRequest(self.id + ' cannot fetch margin adjustments for type ' + type)
8061
+ request: dict = {
8062
+ 'subType': subType,
8063
+ 'mgnMode': 'isolated',
8064
+ }
8065
+ until = self.safe_integer(params, 'until')
8066
+ params = self.omit(params, 'until')
8067
+ if since is not None:
8068
+ request['startTime'] = since
8069
+ if limit is not None:
8070
+ request['limit'] = limit
8071
+ if until is not None:
8072
+ request['endTime'] = until
8073
+ response = None
8074
+ now = self.milliseconds()
8075
+ oneWeekAgo = now - 604800000
8076
+ threeMonthsAgo = now - 7776000000
8077
+ if (since is None) or (since > oneWeekAgo):
8078
+ response = self.privateGetAccountBills(self.extend(request, params))
8079
+ elif since > threeMonthsAgo:
8080
+ response = self.privateGetAccountBillsArchive(self.extend(request, params))
8081
+ else:
8082
+ raise BadRequest(self.id + ' fetchMarginAdjustmentHistory() cannot fetch margin adjustments older than 3 months')
8083
+ #
8084
+ # {
8085
+ # code: '0',
8086
+ # data: [
8087
+ # {
8088
+ # bal: '67621.4325135010619812',
8089
+ # balChg: '-10.0000000000000000',
8090
+ # billId: '691293628710342659',
8091
+ # ccy: 'USDT',
8092
+ # clOrdId: '',
8093
+ # execType: '',
8094
+ # fee: '0',
8095
+ # fillFwdPx: '',
8096
+ # fillIdxPx: '',
8097
+ # fillMarkPx: '',
8098
+ # fillMarkVol: '',
8099
+ # fillPxUsd: '',
8100
+ # fillPxVol: '',
8101
+ # fillTime: '1711089244850',
8102
+ # from: '',
8103
+ # instId: 'XRP-USDT-SWAP',
8104
+ # instType: 'SWAP',
8105
+ # interest: '0',
8106
+ # mgnMode: 'isolated',
8107
+ # notes: '',
8108
+ # ordId: '',
8109
+ # pnl: '0',
8110
+ # posBal: '73.12',
8111
+ # posBalChg: '10.00',
8112
+ # px: '',
8113
+ # subType: '160',
8114
+ # sz: '10',
8115
+ # tag: '',
8116
+ # to: '',
8117
+ # tradeId: '0',
8118
+ # ts: '1711089244699',
8119
+ # type: '6'
8120
+ # }
8121
+ # ],
8122
+ # msg: ''
8123
+ # }
8124
+ #
8125
+ data = self.safe_list(response, 'data')
8126
+ modifications = self.parse_margin_modifications(data)
8127
+ return self.filter_by_symbol_since_limit(modifications, symbol, since, limit)
8128
+
8129
+ def fetch_positions_history(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
8130
+ """
8131
+ fetches historical positions
8132
+
8133
+ https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-positions-history
8134
+
8135
+ :param str [symbols]: unified market symbols
8136
+ :param int [since]: timestamp in ms of the earliest position to fetch
8137
+ :param int [limit]: the maximum amount of records to fetch, default=100, max=100
8138
+ :param dict params: extra parameters specific to the exchange api endpoint
8139
+ :param str [params.marginMode]: "cross" or "isolated"
8140
+
8141
+ EXCHANGE SPECIFIC PARAMETERS
8142
+ :param str [params.instType]: margin, swap, futures or option
8143
+ :param str [params.type]: the type of latest close position 1: close position partially, 2:close all, 3:liquidation, 4:partial liquidation; 5:adl, is it is the latest type if there are several types for the same position
8144
+ :param str [params.posId]: position id, there is attribute expiration, the posid will be expired if it is more than 30 days after the last full close position, then position will use new posid
8145
+ :param str [params.before]: timestamp in ms of the earliest position to fetch based on the last update time of the position
8146
+ :param str [params.after]: timestamp in ms of the latest position to fetch based on the last update time of the position
8147
+ :returns dict[]: a list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
8148
+ """
8149
+ self.load_markets()
8150
+ marginMode = self.safe_string(params, 'marginMode')
8151
+ instType = self.safe_string_upper(params, 'instType')
8152
+ params = self.omit(params, ['until', 'marginMode', 'instType'])
8153
+ if limit is None:
8154
+ limit = 100
8155
+ request: dict = {
8156
+ 'limit': limit,
8157
+ }
8158
+ if symbols is not None:
8159
+ symbolsLength = len(symbols)
8160
+ if symbolsLength == 1:
8161
+ market = self.market(symbols[0])
8162
+ request['instId'] = market['id']
8163
+ if marginMode is not None:
8164
+ request['mgnMode'] = marginMode
8165
+ if instType is not None:
8166
+ request['instType'] = instType
8167
+ response = self.privateGetAccountPositionsHistory(self.extend(request, params))
8168
+ #
8169
+ # {
8170
+ # code: '0',
8171
+ # data: [
8172
+ # {
8173
+ # cTime: '1708735940395',
8174
+ # ccy: 'USDT',
8175
+ # closeAvgPx: '0.6330444444444444',
8176
+ # closeTotalPos: '27',
8177
+ # direction: 'long',
8178
+ # fee: '-1.69566',
8179
+ # fundingFee: '-11.870404179341788',
8180
+ # instId: 'XRP-USDT-SWAP',
8181
+ # instType: 'SWAP',
8182
+ # lever: '3.0',
8183
+ # liqPenalty: '0',
8184
+ # mgnMode: 'cross',
8185
+ # openAvgPx: '0.623',
8186
+ # openMaxPos: '15',
8187
+ # pnl: '27.11999999999988',
8188
+ # pnlRatio: '0.0241732402722634',
8189
+ # posId: '681423155054862336',
8190
+ # realizedPnl: '13.553935820658092',
8191
+ # triggerPx: '',
8192
+ # type: '2',
8193
+ # uTime: '1711088748170',
8194
+ # uly: 'XRP-USDT'
8195
+ # },
8196
+ # ...
8197
+ # ],
8198
+ # msg: ''
8199
+ # }
8200
+ #
8201
+ data = self.safe_list(response, 'data')
8202
+ positions = self.parse_positions(data, symbols, params)
8203
+ return self.filter_by_since_limit(positions, since, limit)
8204
+
8205
+ def fetch_long_short_ratio_history(self, symbol: Str = None, timeframe: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LongShortRatio]:
8206
+ """
8207
+ fetches the long short ratio history for a unified market symbol
8208
+
8209
+ https://www.okx.com/docs-v5/en/#trading-statistics-rest-api-get-contract-long-short-ratio
8210
+
8211
+ :param str symbol: unified symbol of the market to fetch the long short ratio for
8212
+ :param str [timeframe]: the period for the ratio
8213
+ :param int [since]: the earliest time in ms to fetch ratios for
8214
+ :param int [limit]: the maximum number of long short ratio structures to retrieve
8215
+ :param dict [params]: extra parameters specific to the exchange API endpoint
8216
+ :param int [params.until]: timestamp in ms of the latest ratio to fetch
8217
+ :returns dict[]: an array of `long short ratio structures <https://docs.ccxt.com/#/?id=long-short-ratio-structure>`
8218
+ """
8219
+ self.load_markets()
8220
+ market = self.market(symbol)
8221
+ request: dict = {
8222
+ 'instId': market['id'],
8223
+ }
8224
+ until = self.safe_string_2(params, 'until', 'end')
8225
+ params = self.omit(params, 'until')
8226
+ if until is not None:
8227
+ request['end'] = until
8228
+ if timeframe is not None:
8229
+ request['period'] = timeframe
8230
+ if since is not None:
8231
+ request['begin'] = since
8232
+ if limit is not None:
8233
+ request['limit'] = limit
8234
+ response = self.publicGetRubikStatContractsLongShortAccountRatioContract(self.extend(request, params))
8235
+ #
8236
+ # {
8237
+ # "code": "0",
8238
+ # "data": [
8239
+ # ["1729323600000", "0.9398602814619824"],
8240
+ # ["1729323300000", "0.9398602814619824"],
8241
+ # ["1729323000000", "0.9398602814619824"],
8242
+ # ],
8243
+ # "msg": ""
8244
+ # }
8245
+ #
8246
+ data = self.safe_list(response, 'data', [])
8247
+ result = []
8248
+ for i in range(0, len(data)):
8249
+ entry = data[i]
8250
+ result.append({
8251
+ 'timestamp': self.safe_string(entry, 0),
8252
+ 'longShortRatio': self.safe_string(entry, 1),
8253
+ })
8254
+ return self.parse_long_short_ratio_history(result, market)
8255
+
8256
+ def parse_long_short_ratio(self, info: dict, market: Market = None) -> LongShortRatio:
8257
+ timestamp = self.safe_integer(info, 'timestamp')
8258
+ symbol = None
8259
+ if market is not None:
8260
+ symbol = market['symbol']
8261
+ return {
8262
+ 'info': info,
8263
+ 'symbol': symbol,
8264
+ 'timestamp': timestamp,
8265
+ 'datetime': self.iso8601(timestamp),
8266
+ 'timeframe': None,
8267
+ 'longShortRatio': self.safe_number(info, 'longShortRatio'),
8268
+ }