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/pro/vertex.py ADDED
@@ -0,0 +1,943 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ import ccxt.async_support
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide
8
+ from ccxt.base.types import Int, Market, Order, OrderBook, Position, Str, Strings, Ticker, Trade
9
+ from ccxt.async_support.base.ws.client import Client
10
+ from typing import List
11
+ from ccxt.base.errors import AuthenticationError
12
+ from ccxt.base.errors import ArgumentsRequired
13
+ from ccxt.base.errors import NotSupported
14
+ from ccxt.base.precise import Precise
15
+
16
+
17
+ class vertex(ccxt.async_support.vertex):
18
+
19
+ def describe(self):
20
+ return self.deep_extend(super(vertex, self).describe(), {
21
+ 'has': {
22
+ 'ws': True,
23
+ 'watchBalance': False,
24
+ 'watchMyTrades': True,
25
+ 'watchOHLCV': False,
26
+ 'watchOrderBook': True,
27
+ 'watchOrders': True,
28
+ 'watchTicker': True,
29
+ 'watchTickers': False,
30
+ 'watchTrades': True,
31
+ 'watchTradesForSymbols': False,
32
+ 'watchPositions': True,
33
+ },
34
+ 'urls': {
35
+ 'api': {
36
+ 'ws': 'wss://gateway.prod.vertexprotocol.com/v1/subscribe',
37
+ },
38
+ 'test': {
39
+ 'ws': 'wss://gateway.sepolia-test.vertexprotocol.com/v1/subscribe',
40
+ },
41
+ },
42
+ 'requiredCredentials': {
43
+ 'apiKey': False,
44
+ 'secret': False,
45
+ 'walletAddress': True,
46
+ 'privateKey': True,
47
+ },
48
+ 'options': {
49
+ 'tradesLimit': 1000,
50
+ 'ordersLimit': 1000,
51
+ 'requestId': {},
52
+ 'watchPositions': {
53
+ 'fetchPositionsSnapshot': True, # or False
54
+ 'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
55
+ },
56
+ 'ws': {
57
+ 'inflate': True,
58
+ },
59
+ },
60
+ 'streaming': {
61
+ # 'ping': self.ping,
62
+ 'keepAlive': 30000,
63
+ },
64
+ 'exceptions': {
65
+ 'ws': {
66
+ 'exact': {
67
+ 'Auth is needed.': AuthenticationError,
68
+ },
69
+ },
70
+ },
71
+ })
72
+
73
+ def request_id(self, url):
74
+ options = self.safe_dict(self.options, 'requestId', {})
75
+ previousValue = self.safe_integer(options, url, 0)
76
+ newValue = self.sum(previousValue, 1)
77
+ self.options['requestId'][url] = newValue
78
+ return newValue
79
+
80
+ async def watch_public(self, messageHash, message):
81
+ url = self.urls['api']['ws']
82
+ requestId = self.request_id(url)
83
+ subscribe = {
84
+ 'id': requestId,
85
+ }
86
+ request = self.extend(subscribe, message)
87
+ wsOptions = {
88
+ 'headers': {
89
+ 'Sec-WebSocket-Extensions': 'permessage-deflate',
90
+ },
91
+ }
92
+ self.options['ws'] = {
93
+ 'options': wsOptions,
94
+ }
95
+ return await self.watch(url, messageHash, request, messageHash, subscribe)
96
+
97
+ async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
98
+ """
99
+ watches information on multiple trades made in a market
100
+
101
+ https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
102
+
103
+ :param str symbol: unified market symbol of the market trades were made in
104
+ :param int [since]: the earliest time in ms to fetch trades for
105
+ :param int [limit]: the maximum number of trade structures to retrieve
106
+ :param dict [params]: extra parameters specific to the exchange API endpoint
107
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
108
+ """
109
+ await self.load_markets()
110
+ market = self.market(symbol)
111
+ name = 'trade'
112
+ topic = market['id'] + '@' + name
113
+ request = {
114
+ 'method': 'subscribe',
115
+ 'stream': {
116
+ 'type': name,
117
+ 'product_id': self.parse_to_numeric(market['id']),
118
+ },
119
+ }
120
+ message = self.extend(request, params)
121
+ trades = await self.watch_public(topic, message)
122
+ if self.newUpdates:
123
+ limit = trades.getLimit(market['symbol'], limit)
124
+ return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
125
+
126
+ def handle_trade(self, client: Client, message):
127
+ #
128
+ # {
129
+ # "type": "trade",
130
+ # "timestamp": "1676151190656903000", # timestamp of the event in nanoseconds
131
+ # "product_id": 1,
132
+ # "price": "1000", # price the trade happened at, multiplied by 1e18
133
+ # # both taker_qty and maker_qty have the same value
134
+ # # set to filled amount(min amount of taker and maker) when matching against book
135
+ # # set to matched amm base amount when matching against amm
136
+ # "taker_qty": "1000",
137
+ # "maker_qty": "1000",
138
+ # "is_taker_buyer": True,
139
+ # "is_maker_amm": True # True when maker is amm
140
+ # }
141
+ #
142
+ topic = self.safe_string(message, 'type')
143
+ marketId = self.safe_string(message, 'product_id')
144
+ trade = self.parse_ws_trade(message)
145
+ symbol = trade['symbol']
146
+ if not (symbol in self.trades):
147
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
148
+ stored = ArrayCache(limit)
149
+ self.trades[symbol] = stored
150
+ trades = self.trades[symbol]
151
+ trades.append(trade)
152
+ self.trades[symbol] = trades
153
+ client.resolve(trades, marketId + '@' + topic)
154
+
155
+ async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
156
+ """
157
+ watches information on multiple trades made by the user
158
+
159
+ https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
160
+
161
+ :param str symbol: unified market symbol of the market orders were made in
162
+ :param int [since]: the earliest time in ms to fetch orders for
163
+ :param int [limit]: the maximum number of order structures to retrieve
164
+ :param dict [params]: extra parameters specific to the exchange API endpoint
165
+ :param str [params.user]: user address, will default to self.walletAddress if not provided
166
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
167
+ """
168
+ if symbol is None:
169
+ raise ArgumentsRequired(self.id + ' watchMyTrades requires a symbol.')
170
+ await self.load_markets()
171
+ userAddress = None
172
+ userAddress, params = self.handlePublicAddress('watchMyTrades', params)
173
+ market = self.market(symbol)
174
+ name = 'fill'
175
+ topic = market['id'] + '@' + name
176
+ request = {
177
+ 'method': 'subscribe',
178
+ 'stream': {
179
+ 'type': name,
180
+ 'product_id': self.parse_to_numeric(market['id']),
181
+ 'subaccount': self.convertAddressToSender(userAddress),
182
+ },
183
+ }
184
+ message = self.extend(request, params)
185
+ trades = await self.watch_public(topic, message)
186
+ if self.newUpdates:
187
+ limit = trades.getLimit(symbol, limit)
188
+ return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
189
+
190
+ def handle_my_trades(self, client: Client, message):
191
+ #
192
+ # {
193
+ # "type": "fill",
194
+ # "timestamp": "1676151190656903000", # timestamp of the event in nanoseconds
195
+ # "product_id": 1,
196
+ # # the subaccount that placed self order
197
+ # "subaccount": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
198
+ # # hash of the order that uniquely identifies it
199
+ # "order_digest": "0xf4f7a8767faf0c7f72251a1f9e5da590f708fd9842bf8fcdeacbaa0237958fff",
200
+ # # the amount filled, multiplied by 1e18
201
+ # "filled_qty": "1000",
202
+ # # the amount outstanding unfilled, multiplied by 1e18
203
+ # "remaining_qty": "2000",
204
+ # # the original order amount, multiplied by 1e18
205
+ # "original_qty": "3000",
206
+ # # fill price
207
+ # "price": "24991000000000000000000",
208
+ # # True for `taker`, False for `maker`
209
+ # "is_taker": True,
210
+ # "is_bid": True,
211
+ # # True when matching against amm
212
+ # "is_against_amm": True,
213
+ # # an optional `order id` that can be provided when placing an order
214
+ # "id": 100
215
+ # }
216
+ #
217
+ topic = self.safe_string(message, 'type')
218
+ marketId = self.safe_string(message, 'product_id')
219
+ if self.myTrades is None:
220
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
221
+ self.myTrades = ArrayCacheBySymbolById(limit)
222
+ trades = self.myTrades
223
+ parsed = self.parse_ws_trade(message)
224
+ trades.append(parsed)
225
+ client.resolve(trades, marketId + '@' + topic)
226
+
227
+ def parse_ws_trade(self, trade, market=None):
228
+ #
229
+ # watchTrades
230
+ # {
231
+ # "type": "trade",
232
+ # "timestamp": "1676151190656903000", # timestamp of the event in nanoseconds
233
+ # "product_id": 1,
234
+ # "price": "1000", # price the trade happened at, multiplied by 1e18
235
+ # # both taker_qty and maker_qty have the same value
236
+ # # set to filled amount(min amount of taker and maker) when matching against book
237
+ # # set to matched amm base amount when matching against amm
238
+ # "taker_qty": "1000",
239
+ # "maker_qty": "1000",
240
+ # "is_taker_buyer": True,
241
+ # "is_maker_amm": True # True when maker is amm
242
+ # }
243
+ # watchMyTrades
244
+ # {
245
+ # "type": "fill",
246
+ # "timestamp": "1676151190656903000", # timestamp of the event in nanoseconds
247
+ # "product_id": 1,
248
+ # # the subaccount that placed self order
249
+ # "subaccount": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
250
+ # # hash of the order that uniquely identifies it
251
+ # "order_digest": "0xf4f7a8767faf0c7f72251a1f9e5da590f708fd9842bf8fcdeacbaa0237958fff",
252
+ # # the amount filled, multiplied by 1e18
253
+ # "filled_qty": "1000",
254
+ # # the amount outstanding unfilled, multiplied by 1e18
255
+ # "remaining_qty": "2000",
256
+ # # the original order amount, multiplied by 1e18
257
+ # "original_qty": "3000",
258
+ # # fill price
259
+ # "price": "24991000000000000000000",
260
+ # # True for `taker`, False for `maker`
261
+ # "is_taker": True,
262
+ # "is_bid": True,
263
+ # # True when matching against amm
264
+ # "is_against_amm": True,
265
+ # # an optional `order id` that can be provided when placing an order
266
+ # "id": 100
267
+ # }
268
+ #
269
+ marketId = self.safe_string(trade, 'product_id')
270
+ market = self.safe_market(marketId, market)
271
+ symbol = market['symbol']
272
+ price = self.convertFromX18(self.safe_string(trade, 'price'))
273
+ amount = self.convertFromX18(self.safe_string_2(trade, 'taker_qty', 'filled_qty'))
274
+ cost = Precise.string_mul(price, amount)
275
+ timestamp = self.safe_integer_product(trade, 'timestamp', 0.000001)
276
+ takerOrMaker = None
277
+ isTaker = self.safe_bool(trade, 'is_taker')
278
+ if isTaker is not None:
279
+ takerOrMaker = 'taker' if (isTaker) else 'maker'
280
+ side = None
281
+ isBid = self.safe_bool(trade, 'is_bid')
282
+ if isBid is not None:
283
+ side = 'buy' if (isBid) else 'sell'
284
+ return self.safe_trade({
285
+ 'id': None,
286
+ 'timestamp': timestamp,
287
+ 'datetime': self.iso8601(timestamp),
288
+ 'symbol': symbol,
289
+ 'side': side,
290
+ 'price': price,
291
+ 'amount': amount,
292
+ 'cost': cost,
293
+ 'order': self.safe_string_2(trade, 'digest', 'id'),
294
+ 'takerOrMaker': takerOrMaker,
295
+ 'type': None,
296
+ 'fee': None,
297
+ 'info': trade,
298
+ }, market)
299
+
300
+ async def watch_ticker(self, symbol: str, params={}) -> Ticker:
301
+ """
302
+
303
+ https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
304
+
305
+ watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
306
+ :param str symbol: unified symbol of the market to fetch the ticker for
307
+ :param dict [params]: extra parameters specific to the exchange API endpoint
308
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
309
+ """
310
+ await self.load_markets()
311
+ name = 'best_bid_offer'
312
+ market = self.market(symbol)
313
+ topic = market['id'] + '@' + name
314
+ request = {
315
+ 'method': 'subscribe',
316
+ 'stream': {
317
+ 'type': name,
318
+ 'product_id': self.parse_to_numeric(market['id']),
319
+ },
320
+ }
321
+ message = self.extend(request, params)
322
+ return await self.watch_public(topic, message)
323
+
324
+ def parse_ws_ticker(self, ticker, market=None):
325
+ #
326
+ # {
327
+ # "type": "best_bid_offer",
328
+ # "timestamp": "1676151190656903000", # timestamp of the event in nanoseconds
329
+ # "product_id": 1,
330
+ # "bid_price": "1000", # the highest bid price, multiplied by 1e18
331
+ # "bid_qty": "1000", # quantity at the huighest bid, multiplied by 1e18.
332
+ # # i.e. if self is USDC with 6 decimals, one USDC
333
+ # # would be 1e12
334
+ # "ask_price": "1000", # lowest ask price
335
+ # "ask_qty": "1000" # quantity at the lowest ask
336
+ # }
337
+ #
338
+ timestamp = self.safe_integer_product(ticker, 'timestamp', 0.000001)
339
+ return self.safe_ticker({
340
+ 'symbol': self.safe_symbol(None, market),
341
+ 'timestamp': timestamp,
342
+ 'datetime': self.iso8601(timestamp),
343
+ 'high': self.safe_string(ticker, 'high'),
344
+ 'low': self.safe_string(ticker, 'low'),
345
+ 'bid': self.convertFromX18(self.safe_string(ticker, 'bid_price')),
346
+ 'bidVolume': self.convertFromX18(self.safe_string(ticker, 'bid_qty')),
347
+ 'ask': self.convertFromX18(self.safe_string(ticker, 'ask_price')),
348
+ 'askVolume': self.convertFromX18(self.safe_string(ticker, 'ask_qty')),
349
+ 'vwap': None,
350
+ 'open': None,
351
+ 'close': None,
352
+ 'last': None,
353
+ 'previousClose': None,
354
+ 'change': None,
355
+ 'percentage': None,
356
+ 'average': None,
357
+ 'baseVolume': None,
358
+ 'quoteVolume': None,
359
+ 'info': ticker,
360
+ }, market)
361
+
362
+ def handle_ticker(self, client: Client, message):
363
+ #
364
+ # {
365
+ # "type": "best_bid_offer",
366
+ # "timestamp": "1676151190656903000", # timestamp of the event in nanoseconds
367
+ # "product_id": 1,
368
+ # "bid_price": "1000", # the highest bid price, multiplied by 1e18
369
+ # "bid_qty": "1000", # quantity at the huighest bid, multiplied by 1e18.
370
+ # # i.e. if self is USDC with 6 decimals, one USDC
371
+ # # would be 1e12
372
+ # "ask_price": "1000", # lowest ask price
373
+ # "ask_qty": "1000" # quantity at the lowest ask
374
+ # }
375
+ #
376
+ marketId = self.safe_string(message, 'product_id')
377
+ market = self.safe_market(marketId)
378
+ ticker = self.parse_ws_ticker(message, market)
379
+ ticker['symbol'] = market['symbol']
380
+ self.tickers[market['symbol']] = ticker
381
+ client.resolve(ticker, marketId + '@best_bid_offer')
382
+ return message
383
+
384
+ async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
385
+ """
386
+
387
+ https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
388
+
389
+ watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
390
+ :param str symbol: unified symbol of the market to fetch the order book for
391
+ :param int [limit]: the maximum amount of order book entries to return.
392
+ :param dict [params]: extra parameters specific to the exchange API endpoint
393
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
394
+ """
395
+ await self.load_markets()
396
+ name = 'book_depth'
397
+ market = self.market(symbol)
398
+ messageHash = market['id'] + '@' + name
399
+ url = self.urls['api']['ws']
400
+ requestId = self.request_id(url)
401
+ request: dict = {
402
+ 'id': requestId,
403
+ 'method': 'subscribe',
404
+ 'stream': {
405
+ 'type': name,
406
+ 'product_id': self.parse_to_numeric(market['id']),
407
+ },
408
+ }
409
+ subscription: dict = {
410
+ 'id': str(requestId),
411
+ 'name': name,
412
+ 'symbol': symbol,
413
+ 'method': self.handle_order_book_subscription,
414
+ 'limit': limit,
415
+ 'params': params,
416
+ }
417
+ message = self.extend(request, params)
418
+ orderbook = await self.watch(url, messageHash, message, messageHash, subscription)
419
+ return orderbook.limit()
420
+
421
+ def handle_order_book_subscription(self, client: Client, message, subscription):
422
+ defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
423
+ limit = self.safe_integer(subscription, 'limit', defaultLimit)
424
+ symbol = self.safe_string(subscription, 'symbol') # watchOrderBook
425
+ if symbol in self.orderbooks:
426
+ del self.orderbooks[symbol]
427
+ self.orderbooks[symbol] = self.order_book({}, limit)
428
+ self.spawn(self.fetch_order_book_snapshot, client, message, subscription)
429
+
430
+ async def fetch_order_book_snapshot(self, client, message, subscription):
431
+ symbol = self.safe_string(subscription, 'symbol')
432
+ market = self.market(symbol)
433
+ messageHash = market['id'] + '@book_depth'
434
+ try:
435
+ defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
436
+ limit = self.safe_integer(subscription, 'limit', defaultLimit)
437
+ params = self.safe_value(subscription, 'params')
438
+ snapshot = await self.fetch_rest_order_book_safe(symbol, limit, params)
439
+ if self.safe_value(self.orderbooks, symbol) is None:
440
+ # if the orderbook is dropped before the snapshot is received
441
+ return
442
+ orderbook = self.orderbooks[symbol]
443
+ orderbook.reset(snapshot)
444
+ messages = orderbook.cache
445
+ for i in range(0, len(messages)):
446
+ messageItem = messages[i]
447
+ lastTimestamp = self.parse_to_int(Precise.string_div(self.safe_string(messageItem, 'last_max_timestamp'), '1000000'))
448
+ if lastTimestamp < orderbook['timestamp']:
449
+ continue
450
+ else:
451
+ self.handle_order_book_message(client, messageItem, orderbook)
452
+ self.orderbooks[symbol] = orderbook
453
+ client.resolve(orderbook, messageHash)
454
+ except Exception as e:
455
+ del client.subscriptions[messageHash]
456
+ client.reject(e, messageHash)
457
+
458
+ def handle_order_book(self, client: Client, message):
459
+ #
460
+ #
461
+ # the feed does not include a snapshot, just the deltas
462
+ #
463
+ # {
464
+ # "type":"book_depth",
465
+ # # book depth aggregates a number of events once every 50ms
466
+ # # these are the minimum and maximum timestamps from
467
+ # # events that contributed to self response
468
+ # "min_timestamp": "1683805381879572835",
469
+ # "max_timestamp": "1683805381879572835",
470
+ # # the max_timestamp of the last book_depth event for self product
471
+ # "last_max_timestamp": "1683805381771464799",
472
+ # "product_id":1,
473
+ # # changes to the bid side of the book in the form of [[price, new_qty]]
474
+ # "bids":[["21594490000000000000000","51007390115411548"]],
475
+ # # changes to the ask side of the book in the form of [[price, new_qty]]
476
+ # "asks":[["21694490000000000000000","0"],["21695050000000000000000","0"]]
477
+ # }
478
+ #
479
+ marketId = self.safe_string(message, 'product_id')
480
+ market = self.safe_market(marketId)
481
+ symbol = market['symbol']
482
+ if not (symbol in self.orderbooks):
483
+ self.orderbooks[symbol] = self.order_book()
484
+ orderbook = self.orderbooks[symbol]
485
+ timestamp = self.safe_integer(orderbook, 'timestamp')
486
+ if timestamp is None:
487
+ # Buffer the events you receive from the stream.
488
+ orderbook.cache.append(message)
489
+ else:
490
+ lastTimestamp = self.parse_to_int(Precise.string_div(self.safe_string(message, 'last_max_timestamp'), '1000000'))
491
+ if lastTimestamp > timestamp:
492
+ self.handle_order_book_message(client, message, orderbook)
493
+ client.resolve(orderbook, marketId + '@book_depth')
494
+
495
+ def handle_order_book_message(self, client: Client, message, orderbook):
496
+ timestamp = self.parse_to_int(Precise.string_div(self.safe_string(message, 'last_max_timestamp'), '1000000'))
497
+ # convert from X18
498
+ data = {
499
+ 'bids': [],
500
+ 'asks': [],
501
+ }
502
+ bids = self.safe_list(message, 'bids', [])
503
+ for i in range(0, len(bids)):
504
+ bid = bids[i]
505
+ data['bids'].append([
506
+ self.convertFromX18(bid[0]),
507
+ self.convertFromX18(bid[1]),
508
+ ])
509
+ asks = self.safe_list(message, 'asks', [])
510
+ for i in range(0, len(asks)):
511
+ ask = asks[i]
512
+ data['asks'].append([
513
+ self.convertFromX18(ask[0]),
514
+ self.convertFromX18(ask[1]),
515
+ ])
516
+ self.handle_deltas(orderbook['asks'], self.safe_list(data, 'asks', []))
517
+ self.handle_deltas(orderbook['bids'], self.safe_list(data, 'bids', []))
518
+ orderbook['timestamp'] = timestamp
519
+ orderbook['datetime'] = self.iso8601(timestamp)
520
+ return orderbook
521
+
522
+ def handle_delta(self, bookside, delta):
523
+ price = self.safe_float(delta, 0)
524
+ amount = self.safe_float(delta, 1)
525
+ bookside.store(price, amount)
526
+
527
+ def handle_deltas(self, bookside, deltas):
528
+ for i in range(0, len(deltas)):
529
+ self.handle_delta(bookside, deltas[i])
530
+
531
+ def handle_subscription_status(self, client: Client, message):
532
+ #
533
+ # {
534
+ # "result": null,
535
+ # "id": 1574649734450
536
+ # }
537
+ #
538
+ id = self.safe_string(message, 'id')
539
+ subscriptionsById = self.index_by(client.subscriptions, 'id')
540
+ subscription = self.safe_value(subscriptionsById, id, {})
541
+ method = self.safe_value(subscription, 'method')
542
+ if method is not None:
543
+ method(client, message, subscription)
544
+ return message
545
+
546
+ async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
547
+ """
548
+
549
+ https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
550
+
551
+ watch all open positions
552
+ :param str[]|None symbols: list of unified market symbols
553
+ @param since
554
+ @param limit
555
+ :param dict params: extra parameters specific to the exchange API endpoint
556
+ :param str [params.user]: user address, will default to self.walletAddress if not provided
557
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
558
+ """
559
+ await self.load_markets()
560
+ symbols = self.market_symbols(symbols)
561
+ if not self.is_empty(symbols):
562
+ if len(symbols) > 1:
563
+ raise NotSupported(self.id + ' watchPositions require only one symbol.')
564
+ else:
565
+ raise ArgumentsRequired(self.id + ' watchPositions require one symbol.')
566
+ userAddress = None
567
+ userAddress, params = self.handlePublicAddress('watchPositions', params)
568
+ url = self.urls['api']['ws']
569
+ client = self.client(url)
570
+ self.set_positions_cache(client, symbols, params)
571
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
572
+ awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True)
573
+ if fetchPositionsSnapshot and awaitPositionsSnapshot and self.positions is None:
574
+ snapshot = await client.future('fetchPositionsSnapshot')
575
+ return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
576
+ name = 'position_change'
577
+ market = self.market(symbols[0])
578
+ topic = market['id'] + '@' + name
579
+ request = {
580
+ 'method': 'subscribe',
581
+ 'stream': {
582
+ 'type': name,
583
+ 'product_id': self.parse_to_numeric(market['id']),
584
+ 'subaccount': self.convertAddressToSender(userAddress),
585
+ },
586
+ }
587
+ message = self.extend(request, params)
588
+ newPositions = await self.watch_public(topic, message)
589
+ if self.newUpdates:
590
+ limit = newPositions.getLimit(symbols[0], limit)
591
+ return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
592
+
593
+ def set_positions_cache(self, client: Client, symbols: Strings = None, params={}):
594
+ fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', False)
595
+ if fetchPositionsSnapshot:
596
+ messageHash = 'fetchPositionsSnapshot'
597
+ if not (messageHash in client.futures):
598
+ client.future(messageHash)
599
+ self.spawn(self.load_positions_snapshot, client, messageHash, symbols, params)
600
+ else:
601
+ self.positions = ArrayCacheBySymbolBySide()
602
+
603
+ async def load_positions_snapshot(self, client, messageHash, symbols, params):
604
+ positions = await self.fetch_positions(symbols, params)
605
+ self.positions = ArrayCacheBySymbolBySide()
606
+ cache = self.positions
607
+ for i in range(0, len(positions)):
608
+ position = positions[i]
609
+ cache.append(position)
610
+ # don't remove the future from the .futures cache
611
+ future = client.futures[messageHash]
612
+ future.resolve(cache)
613
+ client.resolve(cache, 'positions')
614
+
615
+ def handle_positions(self, client, message):
616
+ #
617
+ # {
618
+ # "type":"position_change",
619
+ # "timestamp": "1676151190656903000", # timestamp of event in nanoseconds
620
+ # "product_id":1,
621
+ # # whether self is a position change for the LP token for self product
622
+ # "is_lp":false,
623
+ # # subaccount who's position changed
624
+ # "subaccount":"0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43706d00000000000000000000",
625
+ # # new amount for self product
626
+ # "amount":"51007390115411548",
627
+ # # new quote balance for self product; zero for everything except non lp perps
628
+ # # the negative of the entry cost of the perp
629
+ # "v_quote_amount":"0"
630
+ # }
631
+ #
632
+ if self.positions is None:
633
+ self.positions = ArrayCacheBySymbolBySide()
634
+ cache = self.positions
635
+ topic = self.safe_string(message, 'type')
636
+ marketId = self.safe_string(message, 'product_id')
637
+ market = self.safe_market(marketId)
638
+ position = self.parse_ws_position(message, market)
639
+ cache.append(position)
640
+ client.resolve(position, marketId + '@' + topic)
641
+
642
+ def parse_ws_position(self, position, market=None):
643
+ #
644
+ # {
645
+ # "type":"position_change",
646
+ # "timestamp": "1676151190656903000", # timestamp of event in nanoseconds
647
+ # "product_id":1,
648
+ # # whether self is a position change for the LP token for self product
649
+ # "is_lp":false,
650
+ # # subaccount who's position changed
651
+ # "subaccount":"0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43706d00000000000000000000",
652
+ # # new amount for self product
653
+ # "amount":"51007390115411548",
654
+ # # new quote balance for self product; zero for everything except non lp perps
655
+ # # the negative of the entry cost of the perp
656
+ # "v_quote_amount":"0"
657
+ # }
658
+ #
659
+ marketId = self.safe_string(position, 'product_id')
660
+ market = self.safe_market(marketId)
661
+ contractSize = self.convertFromX18(self.safe_string(position, 'amount'))
662
+ side = 'buy'
663
+ if Precise.string_lt(contractSize, '1'):
664
+ side = 'sell'
665
+ timestamp = self.parse_to_int(Precise.string_div(self.safe_string(position, 'timestamp'), '1000000'))
666
+ return self.safe_position({
667
+ 'info': position,
668
+ 'id': None,
669
+ 'symbol': self.safe_string(market, 'symbol'),
670
+ 'timestamp': timestamp,
671
+ 'datetime': self.iso8601(timestamp),
672
+ 'lastUpdateTimestamp': None,
673
+ 'initialMargin': None,
674
+ 'initialMarginPercentage': None,
675
+ 'maintenanceMargin': None,
676
+ 'maintenanceMarginPercentage': None,
677
+ 'entryPrice': None,
678
+ 'notional': None,
679
+ 'leverage': None,
680
+ 'unrealizedPnl': None,
681
+ 'contracts': None,
682
+ 'contractSize': self.parse_number(contractSize),
683
+ 'marginRatio': None,
684
+ 'liquidationPrice': None,
685
+ 'markPrice': None,
686
+ 'lastPrice': None,
687
+ 'collateral': None,
688
+ 'marginMode': 'cross',
689
+ 'marginType': None,
690
+ 'side': side,
691
+ 'percentage': None,
692
+ 'hedged': None,
693
+ 'stopLossPrice': None,
694
+ 'takeProfitPrice': None,
695
+ })
696
+
697
+ def handle_auth(self, client: Client, message):
698
+ #
699
+ # {result: null, id: 1}
700
+ #
701
+ messageHash = 'authenticated'
702
+ error = self.safe_string(message, 'error')
703
+ if error is None:
704
+ # client.resolve(message, messageHash)
705
+ future = self.safe_value(client.futures, 'authenticated')
706
+ future.resolve(True)
707
+ else:
708
+ authError = AuthenticationError(self.json(message))
709
+ client.reject(authError, messageHash)
710
+ # allows further authentication attempts
711
+ if messageHash in client.subscriptions:
712
+ del client.subscriptions['authenticated']
713
+
714
+ def build_ws_authentication_sig(self, message, chainId, verifyingContractAddress):
715
+ messageTypes = {
716
+ 'StreamAuthentication': [
717
+ {'name': 'sender', 'type': 'bytes32'},
718
+ {'name': 'expiration', 'type': 'uint64'},
719
+ ],
720
+ }
721
+ return self.buildSig(chainId, messageTypes, message, verifyingContractAddress)
722
+
723
+ async def authenticate(self, params={}):
724
+ self.check_required_credentials()
725
+ url = self.urls['api']['ws']
726
+ client = self.client(url)
727
+ messageHash = 'authenticated'
728
+ future = client.future(messageHash)
729
+ authenticated = self.safe_value(client.subscriptions, messageHash)
730
+ if authenticated is None:
731
+ requestId = self.request_id(url)
732
+ contracts = await self.queryContracts()
733
+ chainId = self.safe_string(contracts, 'chain_id')
734
+ verifyingContractAddress = self.safe_string(contracts, 'endpoint_addr')
735
+ now = self.nonce()
736
+ nonce = now + 90000
737
+ authentication = {
738
+ 'sender': self.convertAddressToSender(self.walletAddress),
739
+ 'expiration': nonce,
740
+ }
741
+ request = {
742
+ 'id': requestId,
743
+ 'method': 'authenticate',
744
+ 'tx': {
745
+ 'sender': authentication['sender'],
746
+ 'expiration': self.number_to_string(authentication['expiration']),
747
+ },
748
+ 'signature': self.build_ws_authentication_sig(authentication, chainId, verifyingContractAddress),
749
+ }
750
+ message = self.extend(request, params)
751
+ self.watch(url, messageHash, message, messageHash)
752
+ return await future
753
+
754
+ async def watch_private(self, messageHash, message, params={}):
755
+ await self.authenticate(params)
756
+ url = self.urls['api']['ws']
757
+ requestId = self.request_id(url)
758
+ subscribe = {
759
+ 'id': requestId,
760
+ }
761
+ request = self.extend(subscribe, message)
762
+ return await self.watch(url, messageHash, request, messageHash, subscribe)
763
+
764
+ async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
765
+ """
766
+ watches information on multiple orders made by the user
767
+
768
+ https://docs.vertexprotocol.com/developer-resources/api/subscriptions/streams
769
+
770
+ :param str symbol: unified market symbol of the market orders were made in
771
+ :param int [since]: the earliest time in ms to fetch orders for
772
+ :param int [limit]: the maximum number of order structures to retrieve
773
+ :param dict [params]: extra parameters specific to the exchange API endpoint
774
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
775
+ """
776
+ if symbol is None:
777
+ raise ArgumentsRequired(self.id + ' watchOrders requires a symbol.')
778
+ self.check_required_credentials()
779
+ await self.load_markets()
780
+ name = 'order_update'
781
+ market = self.market(symbol)
782
+ topic = market['id'] + '@' + name
783
+ request = {
784
+ 'method': 'subscribe',
785
+ 'stream': {
786
+ 'type': name,
787
+ 'subaccount': self.convertAddressToSender(self.walletAddress),
788
+ 'product_id': self.parse_to_numeric(market['id']),
789
+ },
790
+ }
791
+ message = self.extend(request, params)
792
+ orders = await self.watch_private(topic, message)
793
+ if self.newUpdates:
794
+ limit = orders.getLimit(symbol, limit)
795
+ return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
796
+
797
+ def parse_ws_order_status(self, status):
798
+ if status is not None:
799
+ statuses = {
800
+ 'filled': 'open',
801
+ 'placed': 'open',
802
+ 'cancelled': 'canceled',
803
+ }
804
+ return self.safe_string(statuses, status, status)
805
+ return status
806
+
807
+ def parse_ws_order(self, order, market: Market = None) -> Order:
808
+ #
809
+ # {
810
+ # "type": "order_update",
811
+ # # timestamp of the event in nanoseconds
812
+ # "timestamp": "1695081920633151000",
813
+ # "product_id": 1,
814
+ # # order digest
815
+ # "digest": "0xf7712b63ccf70358db8f201e9bf33977423e7a63f6a16f6dab180bdd580f7c6c",
816
+ # # remaining amount to be filled.
817
+ # # will be `0` if the order is either fully filled or cancelled.
818
+ # "amount": "82000000000000000",
819
+ # # any of: "filled", "cancelled", "placed"
820
+ # "reason": "filled"
821
+ # # an optional `order id` that can be provided when placing an order
822
+ # "id": 100
823
+ # }
824
+ #
825
+ marketId = self.safe_string(order, 'product_id')
826
+ timestamp = self.parse_to_int(Precise.string_div(self.safe_string(order, 'timestamp'), '1000000'))
827
+ remainingString = self.convertFromX18(self.safe_string(order, 'amount'))
828
+ remaining = self.parse_to_numeric(remainingString)
829
+ status = self.parse_ws_order_status(self.safe_string(order, 'reason'))
830
+ if Precise.string_eq(remainingString, '0') and status == 'open':
831
+ status = 'closed'
832
+ market = self.safe_market(marketId, market)
833
+ symbol = market['symbol']
834
+ return self.safe_order({
835
+ 'info': order,
836
+ 'id': self.safe_string_2(order, 'digest', 'id'),
837
+ 'clientOrderId': None,
838
+ 'timestamp': timestamp,
839
+ 'datetime': self.iso8601(timestamp),
840
+ 'lastTradeTimestamp': None,
841
+ 'lastUpdateTimestamp': None,
842
+ 'symbol': symbol,
843
+ 'type': None,
844
+ 'timeInForce': None,
845
+ 'postOnly': None,
846
+ 'reduceOnly': None,
847
+ 'side': None,
848
+ 'price': None,
849
+ 'triggerPrice': None,
850
+ 'amount': None,
851
+ 'cost': None,
852
+ 'average': None,
853
+ 'filled': None,
854
+ 'remaining': remaining,
855
+ 'status': status,
856
+ 'fee': None,
857
+ 'trades': None,
858
+ }, market)
859
+
860
+ def handle_order_update(self, client: Client, message):
861
+ #
862
+ # {
863
+ # "type": "order_update",
864
+ # # timestamp of the event in nanoseconds
865
+ # "timestamp": "1695081920633151000",
866
+ # "product_id": 1,
867
+ # # order digest
868
+ # "digest": "0xf7712b63ccf70358db8f201e9bf33977423e7a63f6a16f6dab180bdd580f7c6c",
869
+ # # remaining amount to be filled.
870
+ # # will be `0` if the order is either fully filled or cancelled.
871
+ # "amount": "82000000000000000",
872
+ # # any of: "filled", "cancelled", "placed"
873
+ # "reason": "filled"
874
+ # # an optional `order id` that can be provided when placing an order
875
+ # "id": 100
876
+ # }
877
+ #
878
+ topic = self.safe_string(message, 'type')
879
+ marketId = self.safe_string(message, 'product_id')
880
+ parsed = self.parse_ws_order(message)
881
+ symbol = self.safe_string(parsed, 'symbol')
882
+ orderId = self.safe_string(parsed, 'id')
883
+ if symbol is not None:
884
+ if self.orders is None:
885
+ limit = self.safe_integer(self.options, 'ordersLimit', 1000)
886
+ self.orders = ArrayCacheBySymbolById(limit)
887
+ cachedOrders = self.orders
888
+ orders = self.safe_dict(cachedOrders.hashmap, symbol, {})
889
+ order = self.safe_dict(orders, orderId)
890
+ if order is not None:
891
+ parsed['timestamp'] = self.safe_integer(order, 'timestamp')
892
+ parsed['datetime'] = self.safe_string(order, 'datetime')
893
+ cachedOrders.append(parsed)
894
+ client.resolve(self.orders, marketId + '@' + topic)
895
+
896
+ def handle_error_message(self, client: Client, message):
897
+ #
898
+ # {
899
+ # result: null,
900
+ # error: 'error parsing request: missing field `expiration`',
901
+ # id: 0
902
+ # }
903
+ #
904
+ errorMessage = self.safe_string(message, 'error')
905
+ try:
906
+ if errorMessage is not None:
907
+ feedback = self.id + ' ' + self.json(message)
908
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorMessage, feedback)
909
+ return False
910
+ except Exception as error:
911
+ if isinstance(error, AuthenticationError):
912
+ messageHash = 'authenticated'
913
+ client.reject(error, messageHash)
914
+ if messageHash in client.subscriptions:
915
+ del client.subscriptions[messageHash]
916
+ else:
917
+ client.reject(error)
918
+ return True
919
+
920
+ def handle_message(self, client: Client, message):
921
+ if self.handle_error_message(client, message):
922
+ return
923
+ methods = {
924
+ 'trade': self.handle_trade,
925
+ 'best_bid_offer': self.handle_ticker,
926
+ 'book_depth': self.handle_order_book,
927
+ 'fill': self.handle_my_trades,
928
+ 'position_change': self.handle_positions,
929
+ 'order_update': self.handle_order_update,
930
+ }
931
+ event = self.safe_string(message, 'type')
932
+ method = self.safe_value(methods, event)
933
+ if method is not None:
934
+ method(client, message)
935
+ return
936
+ requestId = self.safe_string(message, 'id')
937
+ if requestId is not None:
938
+ self.handle_subscription_status(client, message)
939
+ return
940
+ # check whether it's authentication
941
+ auth = self.safe_value(client.futures, 'authenticated')
942
+ if auth is not None:
943
+ self.handle_auth(client, message)