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/bitfinex.py CHANGED
@@ -4,13 +4,14 @@
4
4
  # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
5
 
6
6
  import ccxt.async_support
7
- from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById
7
+ from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
8
8
  import hashlib
9
- from ccxt.base.types import Int, Order, OrderBook, Str, Ticker, Trade
9
+ from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
10
10
  from ccxt.async_support.base.ws.client import Client
11
11
  from typing import List
12
12
  from ccxt.base.errors import ExchangeError
13
13
  from ccxt.base.errors import AuthenticationError
14
+ from ccxt.base.errors import ChecksumError
14
15
  from ccxt.base.precise import Precise
15
16
 
16
17
 
@@ -24,14 +25,17 @@ class bitfinex(ccxt.async_support.bitfinex):
24
25
  'watchTickers': False,
25
26
  'watchOrderBook': True,
26
27
  'watchTrades': True,
27
- 'watchBalance': False, # for now
28
- 'watchOHLCV': False, # missing on the exchange side in v1
28
+ 'watchTradesForSymbols': False,
29
+ 'watchMyTrades': True,
30
+ 'watchBalance': True,
31
+ 'watchOHLCV': True,
32
+ 'watchOrders': True,
29
33
  },
30
34
  'urls': {
31
35
  'api': {
32
36
  'ws': {
33
- 'public': 'wss://api-pub.bitfinex.com/ws/1',
34
- 'private': 'wss://api.bitfinex.com/ws/1',
37
+ 'public': 'wss://api-pub.bitfinex.com/ws/2',
38
+ 'private': 'wss://api.bitfinex.com/ws/2',
35
39
  },
36
40
  },
37
41
  },
@@ -39,6 +43,7 @@ class bitfinex(ccxt.async_support.bitfinex):
39
43
  'watchOrderBook': {
40
44
  'prec': 'P0',
41
45
  'freq': 'F0',
46
+ 'checksum': True,
42
47
  },
43
48
  'ordersLimit': 1000,
44
49
  },
@@ -49,15 +54,136 @@ class bitfinex(ccxt.async_support.bitfinex):
49
54
  market = self.market(symbol)
50
55
  marketId = market['id']
51
56
  url = self.urls['api']['ws']['public']
57
+ client = self.client(url)
52
58
  messageHash = channel + ':' + marketId
53
- # channel = 'trades'
54
- request = {
59
+ request: dict = {
55
60
  'event': 'subscribe',
56
61
  'channel': channel,
57
62
  'symbol': marketId,
58
- 'messageHash': messageHash,
59
63
  }
60
- return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
64
+ result = await self.watch(url, messageHash, self.deep_extend(request, params), messageHash, {'checksum': False})
65
+ checksum = self.safe_bool(self.options, 'checksum', True)
66
+ if checksum and not client.subscriptions[messageHash]['checksum'] and (channel == 'book'):
67
+ client.subscriptions[messageHash]['checksum'] = True
68
+ await client.send({
69
+ 'event': 'conf',
70
+ 'flags': 131072,
71
+ })
72
+ return result
73
+
74
+ async def subscribe_private(self, messageHash):
75
+ await self.load_markets()
76
+ await self.authenticate()
77
+ url = self.urls['api']['ws']['private']
78
+ return await self.watch(url, messageHash, None, 1)
79
+
80
+ async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
81
+ """
82
+ watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
83
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
84
+ :param str timeframe: the length of time each candle represents
85
+ :param int [since]: timestamp in ms of the earliest candle to fetch
86
+ :param int [limit]: the maximum amount of candles to fetch
87
+ :param dict [params]: extra parameters specific to the exchange API endpoint
88
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
89
+ """
90
+ await self.load_markets()
91
+ market = self.market(symbol)
92
+ symbol = market['symbol']
93
+ interval = self.safe_string(self.timeframes, timeframe, timeframe)
94
+ channel = 'candles'
95
+ key = 'trade:' + interval + ':' + market['id']
96
+ messageHash = channel + ':' + interval + ':' + market['id']
97
+ request: dict = {
98
+ 'event': 'subscribe',
99
+ 'channel': channel,
100
+ 'key': key,
101
+ }
102
+ url = self.urls['api']['ws']['public']
103
+ # not using subscribe here because self message has a different format
104
+ ohlcv = await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
105
+ if self.newUpdates:
106
+ limit = ohlcv.getLimit(symbol, limit)
107
+ return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
108
+
109
+ def handle_ohlcv(self, client: Client, message, subscription):
110
+ #
111
+ # initial snapshot
112
+ # [
113
+ # 341527, # channel id
114
+ # [
115
+ # [
116
+ # 1654705860000, # timestamp
117
+ # 1802.6, # open
118
+ # 1800.3, # close
119
+ # 1802.8, # high
120
+ # 1800.3, # low
121
+ # 86.49588236 # volume
122
+ # ],
123
+ # [
124
+ # 1654705800000,
125
+ # 1803.6,
126
+ # 1802.6,
127
+ # 1804.9,
128
+ # 1802.3,
129
+ # 74.6348086
130
+ # ],
131
+ # [
132
+ # 1654705740000,
133
+ # 1802.5,
134
+ # 1803.2,
135
+ # 1804.4,
136
+ # 1802.4,
137
+ # 23.61801085
138
+ # ]
139
+ # ]
140
+ # ]
141
+ #
142
+ # update
143
+ # [
144
+ # 211171,
145
+ # [
146
+ # 1654705680000,
147
+ # 1801,
148
+ # 1802.4,
149
+ # 1802.9,
150
+ # 1800.4,
151
+ # 23.91911091
152
+ # ]
153
+ # ]
154
+ #
155
+ data = self.safe_value(message, 1, [])
156
+ ohlcvs = None
157
+ first = self.safe_value(data, 0)
158
+ if isinstance(first, list):
159
+ # snapshot
160
+ ohlcvs = data
161
+ else:
162
+ # update
163
+ ohlcvs = [data]
164
+ channel = self.safe_value(subscription, 'channel')
165
+ key = self.safe_string(subscription, 'key')
166
+ keyParts = key.split(':')
167
+ interval = self.safe_string(keyParts, 1)
168
+ marketId = key
169
+ marketId = marketId.replace('trade:', '')
170
+ marketId = marketId.replace(interval + ':', '')
171
+ market = self.safe_market(marketId)
172
+ timeframe = self.find_timeframe(interval)
173
+ symbol = market['symbol']
174
+ messageHash = channel + ':' + interval + ':' + marketId
175
+ self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
176
+ stored = self.safe_value(self.ohlcvs[symbol], timeframe)
177
+ if stored is None:
178
+ limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
179
+ stored = ArrayCacheByTimestamp(limit)
180
+ self.ohlcvs[symbol][timeframe] = stored
181
+ ohlcvsLength = len(ohlcvs)
182
+ for i in range(0, ohlcvsLength):
183
+ ohlcv = ohlcvs[ohlcvsLength - i - 1]
184
+ parsed = self.parse_ohlcv(ohlcv, market)
185
+ stored.append(parsed)
186
+ client.resolve(stored, messageHash)
61
187
 
62
188
  async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
63
189
  """
@@ -68,13 +194,30 @@ class bitfinex(ccxt.async_support.bitfinex):
68
194
  :param dict [params]: extra parameters specific to the exchange API endpoint
69
195
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
70
196
  """
71
- await self.load_markets()
72
- symbol = self.symbol(symbol)
73
197
  trades = await self.subscribe('trades', symbol, params)
74
198
  if self.newUpdates:
75
199
  limit = trades.getLimit(symbol, limit)
76
200
  return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
77
201
 
202
+ async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
203
+ """
204
+ watches information on multiple trades made by the user
205
+ :param str symbol: unified market symbol of the market trades were made in
206
+ :param int [since]: the earliest time in ms to fetch trades for
207
+ :param int [limit]: the maximum number of trade structures to retrieve
208
+ :param dict [params]: extra parameters specific to the exchange API endpoint
209
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
210
+ """
211
+ await self.load_markets()
212
+ messageHash = 'myTrade'
213
+ if symbol is not None:
214
+ market = self.market(symbol)
215
+ messageHash += ':' + market['id']
216
+ trades = await self.subscribe_private(messageHash)
217
+ if self.newUpdates:
218
+ limit = trades.getLimit(symbol, limit)
219
+ return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
220
+
78
221
  async def watch_ticker(self, symbol: str, params={}) -> Ticker:
79
222
  """
80
223
  watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
@@ -84,91 +227,188 @@ class bitfinex(ccxt.async_support.bitfinex):
84
227
  """
85
228
  return await self.subscribe('ticker', symbol, params)
86
229
 
87
- def handle_trades(self, client: Client, message, subscription):
88
- #
89
- # initial snapshot
230
+ def handle_my_trade(self, client: Client, message, subscription={}):
90
231
  #
232
+ # trade execution
233
+ # [
234
+ # 0,
235
+ # "te", # or tu
91
236
  # [
92
- # 2,
93
- # [
94
- # [null, 1580565020, 9374.9, 0.005],
95
- # [null, 1580565004, 9374.9, 0.005],
96
- # [null, 1580565003, 9374.9, 0.005],
97
- # ]
237
+ # 1133411090,
238
+ # "tLTCUST",
239
+ # 1655110144598,
240
+ # 97084883506,
241
+ # 0.1,
242
+ # 42.821,
243
+ # "EXCHANGE MARKET",
244
+ # 42.799,
245
+ # -1,
246
+ # null,
247
+ # null,
248
+ # 1655110144596
98
249
  # ]
250
+ # ]
99
251
  #
100
- # when a trade does not have an id yet
252
+ name = 'myTrade'
253
+ data = self.safe_value(message, 2)
254
+ trade = self.parse_ws_trade(data)
255
+ symbol = trade['symbol']
256
+ market = self.market(symbol)
257
+ messageHash = name + ':' + market['id']
258
+ if self.myTrades is None:
259
+ limit = self.safe_integer(self.options, 'tradesLimit', 1000)
260
+ self.myTrades = ArrayCacheBySymbolById(limit)
261
+ tradesArray = self.myTrades
262
+ tradesArray.append(trade)
263
+ self.myTrades = tradesArray
264
+ # generic subscription
265
+ client.resolve(tradesArray, name)
266
+ # specific subscription
267
+ client.resolve(tradesArray, messageHash)
268
+
269
+ def handle_trades(self, client: Client, message, subscription):
270
+ #
271
+ # initial snapshot
101
272
  #
102
- # # channel id, update type, seq, time, price, amount
103
- # [2, "te", "28462857-BTCUSD", 1580565041, 9374.9, 0.005],
273
+ # [
274
+ # 188687, # channel id
275
+ # [
276
+ # [1128060675, 1654701572690, 0.00217533, 1815.3], # id, mts, amount, price
277
+ # [1128060665, 1654701551231, -0.00280472, 1814.1],
278
+ # [1128060664, 1654701550996, -0.00364444, 1814.1],
279
+ # [1128060656, 1654701527730, -0.00265203, 1814.2],
280
+ # [1128060647, 1654701505193, 0.00262395, 1815.2],
281
+ # [1128060642, 1654701484656, -0.13411443, 1816],
282
+ # [1128060641, 1654701484656, -0.00088557, 1816],
283
+ # [1128060639, 1654701478326, -0.002, 1816],
284
+ # ]
285
+ # ]
286
+ # update
104
287
  #
105
- # when a trade already has an id
288
+ # [
289
+ # 360141,
290
+ # "te",
291
+ # [
292
+ # 1128060969, # id
293
+ # 1654702500098, # mts
294
+ # 0.00325131, # amount positive buy, negative sell
295
+ # 1818.5, # price
296
+ # ],
297
+ # ]
106
298
  #
107
- # # channel id, update type, seq, trade id, time, price, amount
108
- # [2, "tu", "28462857-BTCUSD", 413357662, 1580565041, 9374.9, 0.005]
109
299
  #
110
300
  channel = self.safe_value(subscription, 'channel')
111
- marketId = self.safe_string(subscription, 'pair')
301
+ marketId = self.safe_string(subscription, 'symbol')
302
+ market = self.safe_market(marketId)
112
303
  messageHash = channel + ':' + marketId
113
304
  tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
114
- market = self.safe_market(marketId)
115
305
  symbol = market['symbol']
116
- data = self.safe_value(message, 1)
117
306
  stored = self.safe_value(self.trades, symbol)
118
307
  if stored is None:
119
308
  stored = ArrayCache(tradesLimit)
120
309
  self.trades[symbol] = stored
121
- if isinstance(data, list):
122
- trades = self.parse_trades(data, market)
123
- for i in range(0, len(trades)):
124
- stored.append(trades[i])
310
+ messageLength = len(message)
311
+ if messageLength == 2:
312
+ # initial snapshot
313
+ trades = self.safe_list(message, 1, [])
314
+ # needs to be reversed to make chronological order
315
+ length = len(trades)
316
+ for i in range(0, length):
317
+ index = length - i - 1
318
+ parsed = self.parse_ws_trade(trades[index], market)
319
+ stored.append(parsed)
125
320
  else:
126
- second = self.safe_string(message, 1)
127
- if second != 'tu':
321
+ # update
322
+ type = self.safe_string(message, 1)
323
+ if type == 'tu':
324
+ # don't resolve for a duplicate update
325
+ # since te and tu updates are duplicated on the public stream
128
326
  return
129
- trade = self.parse_trade(message, market)
130
- stored.append(trade)
327
+ trade = self.safe_value(message, 2, [])
328
+ parsed = self.parse_ws_trade(trade, market)
329
+ stored.append(parsed)
131
330
  client.resolve(stored, messageHash)
132
331
 
133
- def parse_trade(self, trade, market=None) -> Trade:
134
- #
135
- # snapshot trade
332
+ def parse_ws_trade(self, trade, market=None):
136
333
  #
137
- # # null, time, price, amount
138
- # [null, 1580565020, 9374.9, 0.005],
334
+ # [
335
+ # 1128060969, # id
336
+ # 1654702500098, # mts
337
+ # 0.00325131, # amount positive buy, negative sell
338
+ # 1818.5, # price
339
+ # ]
139
340
  #
140
- # when a trade does not have an id yet
341
+ # trade execution
141
342
  #
142
- # # channel id, update type, seq, time, price, amount
143
- # [2, "te", "28462857-BTCUSD", 1580565041, 9374.9, 0.005],
343
+ # [
344
+ # 1133411090, # id
345
+ # "tLTCUST", # symbol
346
+ # 1655110144598, # create ms
347
+ # 97084883506, # order id
348
+ # 0.1, # amount
349
+ # 42.821, # price
350
+ # "EXCHANGE MARKET", # order type
351
+ # 42.799, # order price
352
+ # -1, # maker
353
+ # null, # fee
354
+ # null, # fee currency
355
+ # 1655110144596 # cid
356
+ # ]
144
357
  #
145
- # when a trade already has an id
358
+ # trade update
146
359
  #
147
- # # channel id, update type, seq, trade id, time, price, amount
148
- # [2, "tu", "28462857-BTCUSD", 413357662, 1580565041, 9374.9, 0.005]
360
+ # [
361
+ # 1133411090,
362
+ # "tLTCUST",
363
+ # 1655110144598,
364
+ # 97084883506,
365
+ # 0.1,
366
+ # 42.821,
367
+ # "EXCHANGE MARKET",
368
+ # 42.799,
369
+ # -1,
370
+ # -0.0002,
371
+ # "LTC",
372
+ # 1655110144596
373
+ # ]
149
374
  #
150
- if not isinstance(trade, list):
151
- return super(bitfinex, self).parse_trade(trade, market)
152
- tradeLength = len(trade)
153
- event = self.safe_string(trade, 1)
154
- id = None
155
- if event == 'tu':
156
- id = self.safe_string(trade, tradeLength - 4)
157
- timestamp = self.safe_timestamp(trade, tradeLength - 3)
158
- price = self.safe_string(trade, tradeLength - 2)
159
- amount = self.safe_string(trade, tradeLength - 1)
375
+ numFields = len(trade)
376
+ isPublic = numFields <= 8
377
+ marketId = self.safe_string(trade, 1) if (not isPublic) else None
378
+ market = self.safe_market(marketId, market)
379
+ createdKey = 1 if isPublic else 2
380
+ priceKey = 3 if isPublic else 5
381
+ amountKey = 2 if isPublic else 4
382
+ marketId = market['id']
383
+ type = self.safe_string(trade, 6)
384
+ if type is not None:
385
+ if type.find('LIMIT') > -1:
386
+ type = 'limit'
387
+ elif type.find('MARKET') > -1:
388
+ type = 'market'
389
+ orderId = self.safe_string(trade, 3) if (not isPublic) else None
390
+ id = self.safe_string(trade, 0)
391
+ timestamp = self.safe_integer(trade, createdKey)
392
+ price = self.safe_string(trade, priceKey)
393
+ amountString = self.safe_string(trade, amountKey)
394
+ amount = self.parse_number(Precise.string_abs(amountString))
160
395
  side = None
161
396
  if amount is not None:
162
- side = 'buy' if Precise.string_gt(amount, '0') else 'sell'
163
- amount = Precise.string_abs(amount)
164
- seq = self.safe_string(trade, 2)
165
- parts = seq.split('-')
166
- marketId = self.safe_string(parts, 1)
167
- if marketId is not None:
168
- marketId = marketId.replace('t', '')
397
+ side = 'buy' if Precise.string_gt(amountString, '0') else 'sell'
169
398
  symbol = self.safe_symbol(marketId, market)
399
+ feeValue = self.safe_string(trade, 9)
400
+ fee = None
401
+ if feeValue is not None:
402
+ currencyId = self.safe_string(trade, 10)
403
+ code = self.safe_currency_code(currencyId)
404
+ fee = {
405
+ 'cost': feeValue,
406
+ 'currency': code,
407
+ }
408
+ maker = self.safe_integer(trade, 8)
170
409
  takerOrMaker = None
171
- orderId = None
410
+ if maker is not None:
411
+ takerOrMaker = 'taker' if (maker == -1) else 'maker'
172
412
  return self.safe_trade({
173
413
  'info': trade,
174
414
  'timestamp': timestamp,
@@ -176,19 +416,20 @@ class bitfinex(ccxt.async_support.bitfinex):
176
416
  'symbol': symbol,
177
417
  'id': id,
178
418
  'order': orderId,
179
- 'type': None,
419
+ 'type': type,
180
420
  'takerOrMaker': takerOrMaker,
181
421
  'side': side,
182
422
  'price': price,
183
423
  'amount': amount,
184
424
  'cost': None,
185
- 'fee': None,
186
- })
425
+ 'fee': fee,
426
+ }, market)
187
427
 
188
428
  def handle_ticker(self, client: Client, message, subscription):
189
429
  #
430
+ # [
431
+ # 340432, # channel ID
190
432
  # [
191
- # 2, # 0 CHANNEL_ID integer Channel ID
192
433
  # 236.62, # 1 BID float Price of last highest bid
193
434
  # 9.0029, # 2 BID_SIZE float Size of the last highest bid
194
435
  # 236.88, # 3 ASK float Price of last lowest ask
@@ -200,40 +441,59 @@ class bitfinex(ccxt.async_support.bitfinex):
200
441
  # 250.01, # 9 HIGH float Daily high
201
442
  # 220.05, # 10 LOW float Daily low
202
443
  # ]
444
+ # ]
203
445
  #
204
- marketId = self.safe_string(subscription, 'pair')
446
+ ticker = self.safe_value(message, 1)
447
+ marketId = self.safe_string(subscription, 'symbol')
448
+ market = self.safe_market(marketId)
205
449
  symbol = self.safe_symbol(marketId)
450
+ parsed = self.parse_ws_ticker(ticker, market)
206
451
  channel = 'ticker'
207
452
  messageHash = channel + ':' + marketId
208
- last = self.safe_string(message, 7)
209
- change = self.safe_string(message, 5)
210
- open = None
211
- if (last is not None) and (change is not None):
212
- open = Precise.string_sub(last, change)
213
- result = {
453
+ self.tickers[symbol] = parsed
454
+ client.resolve(parsed, messageHash)
455
+
456
+ def parse_ws_ticker(self, ticker, market=None):
457
+ #
458
+ # [
459
+ # 236.62, # 1 BID float Price of last highest bid
460
+ # 9.0029, # 2 BID_SIZE float Size of the last highest bid
461
+ # 236.88, # 3 ASK float Price of last lowest ask
462
+ # 7.1138, # 4 ASK_SIZE float Size of the last lowest ask
463
+ # -1.02, # 5 DAILY_CHANGE float Amount that the last price has changed since yesterday
464
+ # 0, # 6 DAILY_CHANGE_PERC float Amount that the price has changed expressed in percentage terms
465
+ # 236.52, # 7 LAST_PRICE float Price of the last trade.
466
+ # 5191.36754297, # 8 VOLUME float Daily volume
467
+ # 250.01, # 9 HIGH float Daily high
468
+ # 220.05, # 10 LOW float Daily low
469
+ # ]
470
+ #
471
+ market = self.safe_market(None, market)
472
+ symbol = market['symbol']
473
+ last = self.safe_string(ticker, 6)
474
+ change = self.safe_string(ticker, 4)
475
+ return self.safe_ticker({
214
476
  'symbol': symbol,
215
477
  'timestamp': None,
216
478
  'datetime': None,
217
- 'high': self.safe_float(message, 9),
218
- 'low': self.safe_float(message, 10),
219
- 'bid': self.safe_float(message, 1),
220
- 'bidVolume': None,
221
- 'ask': self.safe_float(message, 3),
222
- 'askVolume': None,
479
+ 'high': self.safe_string(ticker, 8),
480
+ 'low': self.safe_string(ticker, 9),
481
+ 'bid': self.safe_string(ticker, 0),
482
+ 'bidVolume': self.safe_string(ticker, 1),
483
+ 'ask': self.safe_string(ticker, 2),
484
+ 'askVolume': self.safe_string(ticker, 3),
223
485
  'vwap': None,
224
- 'open': self.parse_number(open),
225
- 'close': self.parse_number(last),
226
- 'last': self.parse_number(last),
486
+ 'open': None,
487
+ 'close': last,
488
+ 'last': last,
227
489
  'previousClose': None,
228
- 'change': self.parse_number(change),
229
- 'percentage': self.safe_float(message, 6),
490
+ 'change': change,
491
+ 'percentage': self.safe_string(ticker, 5),
230
492
  'average': None,
231
- 'baseVolume': self.safe_float(message, 8),
493
+ 'baseVolume': self.safe_string(ticker, 7),
232
494
  'quoteVolume': None,
233
- 'info': message,
234
- }
235
- self.tickers[symbol] = result
236
- client.resolve(result, messageHash)
495
+ 'info': ticker,
496
+ }, market)
237
497
 
238
498
  async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
239
499
  """
@@ -249,14 +509,12 @@ class bitfinex(ccxt.async_support.bitfinex):
249
509
  options = self.safe_value(self.options, 'watchOrderBook', {})
250
510
  prec = self.safe_string(options, 'prec', 'P0')
251
511
  freq = self.safe_string(options, 'freq', 'F0')
252
- request = {
253
- # "event": "subscribe", # added in subscribe()
254
- # "channel": channel, # added in subscribe()
255
- # "symbol": marketId, # added in subscribe()
512
+ request: dict = {
256
513
  'prec': prec, # string, level of price aggregation, 'P0', 'P1', 'P2', 'P3', 'P4', default P0
257
514
  'freq': freq, # string, frequency of updates 'F0' = realtime, 'F1' = 2 seconds, default is 'F0'
258
- 'len': limit, # string, number of price points, '25', '100', default = '25'
259
515
  }
516
+ if limit is not None:
517
+ request['len'] = limit # string, number of price points, '25', '100', default = '25'
260
518
  orderbook = await self.subscribe('book', symbol, self.deep_extend(request, params))
261
519
  return orderbook.limit()
262
520
 
@@ -279,20 +537,22 @@ class bitfinex(ccxt.async_support.bitfinex):
279
537
  # subsequent updates
280
538
  #
281
539
  # [
282
- # 30, # channel id
283
- # 9339.9, # price
284
- # 0, # count
285
- # -1, # size > 0 = bid, size < 0 = ask
540
+ # 358169, # channel id
541
+ # [
542
+ # 1807.1, # price
543
+ # 0, # cound
544
+ # 1 # size
545
+ # ]
286
546
  # ]
287
547
  #
288
- marketId = self.safe_string(subscription, 'pair')
548
+ marketId = self.safe_string(subscription, 'symbol')
289
549
  symbol = self.safe_symbol(marketId)
290
550
  channel = 'book'
291
551
  messageHash = channel + ':' + marketId
292
552
  prec = self.safe_string(subscription, 'prec', 'P0')
293
553
  isRaw = (prec == 'R0')
294
554
  # if it is an initial snapshot
295
- if isinstance(message[1], list):
555
+ if not (symbol in self.orderbooks):
296
556
  limit = self.safe_integer(subscription, 'len')
297
557
  if isRaw:
298
558
  # raw order books
@@ -305,57 +565,211 @@ class bitfinex(ccxt.async_support.bitfinex):
305
565
  deltas = message[1]
306
566
  for i in range(0, len(deltas)):
307
567
  delta = deltas[i]
308
- id = self.safe_string(delta, 0)
309
- price = self.safe_float(delta, 1)
310
- delta2Value = delta[2]
311
- size = -delta2Value if (delta2Value < 0) else delta2Value
312
- side = 'asks' if (delta2Value < 0) else 'bids'
568
+ delta2 = delta[2]
569
+ size = -delta2 if (delta2 < 0) else delta2
570
+ side = 'asks' if (delta2 < 0) else 'bids'
313
571
  bookside = orderbook[side]
314
- bookside.store(price, size, id)
572
+ idString = self.safe_string(delta, 0)
573
+ price = self.safe_float(delta, 1)
574
+ bookside.storeArray([price, size, idString])
315
575
  else:
316
576
  deltas = message[1]
317
577
  for i in range(0, len(deltas)):
318
578
  delta = deltas[i]
319
- delta2 = delta[2]
320
- size = -delta2 if (delta2 < 0) else delta2
321
- side = 'asks' if (delta2 < 0) else 'bids'
322
- countedBookSide = orderbook[side]
323
- countedBookSide.store(delta[0], size, delta[1])
579
+ amount = self.safe_number(delta, 2)
580
+ counter = self.safe_number(delta, 1)
581
+ price = self.safe_number(delta, 0)
582
+ size = -amount if (amount < 0) else amount
583
+ side = 'asks' if (amount < 0) else 'bids'
584
+ bookside = orderbook[side]
585
+ bookside.storeArray([price, size, counter])
586
+ orderbook['symbol'] = symbol
324
587
  client.resolve(orderbook, messageHash)
325
588
  else:
326
589
  orderbook = self.orderbooks[symbol]
590
+ deltas = message[1]
591
+ orderbookItem = self.orderbooks[symbol]
327
592
  if isRaw:
328
- id = self.safe_string(message, 1)
329
- price = self.safe_string(message, 2)
330
- message3 = message[3]
331
- size = -message3 if (message3 < 0) else message3
332
- side = 'asks' if (message3 < 0) else 'bids'
333
- bookside = orderbook[side]
593
+ price = self.safe_string(deltas, 1)
594
+ deltas2 = deltas[2]
595
+ size = -deltas2 if (deltas2 < 0) else deltas2
596
+ side = 'asks' if (deltas2 < 0) else 'bids'
597
+ bookside = orderbookItem[side]
334
598
  # price = 0 means that you have to remove the order from your book
335
599
  amount = size if Precise.string_gt(price, '0') else '0'
336
- bookside.store(self.parse_number(price), self.parse_number(amount), id)
600
+ idString = self.safe_string(deltas, 0)
601
+ bookside.storeArray([self.parse_number(price), self.parse_number(amount), idString])
337
602
  else:
338
- message3Value = message[3]
339
- size = -message3Value if (message3Value < 0) else message3Value
340
- side = 'asks' if (message3Value < 0) else 'bids'
341
- countedBookSide = orderbook[side]
342
- countedBookSide.store(message[1], size, message[2])
603
+ amount = self.safe_string(deltas, 2)
604
+ counter = self.safe_string(deltas, 1)
605
+ price = self.safe_string(deltas, 0)
606
+ size = Precise.string_neg(amount) if Precise.string_lt(amount, '0') else amount
607
+ side = 'asks' if Precise.string_lt(amount, '0') else 'bids'
608
+ bookside = orderbookItem[side]
609
+ bookside.storeArray([self.parse_number(price), self.parse_number(size), self.parse_number(counter)])
343
610
  client.resolve(orderbook, messageHash)
344
611
 
345
- def handle_heartbeat(self, client: Client, message):
612
+ def handle_checksum(self, client: Client, message, subscription):
613
+ #
614
+ # [173904, "cs", -890884919]
615
+ #
616
+ marketId = self.safe_string(subscription, 'symbol')
617
+ symbol = self.safe_symbol(marketId)
618
+ channel = 'book'
619
+ messageHash = channel + ':' + marketId
620
+ book = self.safe_value(self.orderbooks, symbol)
621
+ if book is None:
622
+ return
623
+ depth = 25 # covers the first 25 bids and asks
624
+ stringArray = []
625
+ bids = book['bids']
626
+ asks = book['asks']
627
+ prec = self.safe_string(subscription, 'prec', 'P0')
628
+ isRaw = (prec == 'R0')
629
+ idToCheck = 2 if isRaw else 0
630
+ # pepperoni pizza from bitfinex
631
+ for i in range(0, depth):
632
+ bid = self.safe_value(bids, i)
633
+ ask = self.safe_value(asks, i)
634
+ if bid is not None:
635
+ stringArray.append(self.number_to_string(bids[i][idToCheck]))
636
+ stringArray.append(self.number_to_string(bids[i][1]))
637
+ if ask is not None:
638
+ stringArray.append(self.number_to_string(asks[i][idToCheck]))
639
+ aski1 = asks[i][1]
640
+ stringArray.append(self.number_to_string(-aski1))
641
+ payload = ':'.join(stringArray)
642
+ localChecksum = self.crc32(payload, True)
643
+ responseChecksum = self.safe_integer(message, 2)
644
+ if responseChecksum != localChecksum:
645
+ del client.subscriptions[messageHash]
646
+ del self.orderbooks[symbol]
647
+ checksum = self.handle_option('watchOrderBook', 'checksum', True)
648
+ if checksum:
649
+ error = ChecksumError(self.id + ' ' + self.orderbook_checksum_message(symbol))
650
+ client.reject(error, messageHash)
651
+
652
+ async def watch_balance(self, params={}) -> Balances:
653
+ """
654
+ watch balance and get the amount of funds available for trading or funds locked in orders
655
+ :param dict [params]: extra parameters specific to the exchange API endpoint
656
+ :param str [params.type]: spot or contract if not provided self.options['defaultType'] is used
657
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
658
+ """
659
+ await self.load_markets()
660
+ balanceType = self.safe_string(params, 'wallet', 'exchange') # exchange, margin
661
+ params = self.omit(params, 'wallet')
662
+ messageHash = 'balance:' + balanceType
663
+ return await self.subscribe_private(messageHash)
664
+
665
+ def handle_balance(self, client: Client, message, subscription):
346
666
  #
347
- # every second(approx) if no other updates are sent
667
+ # snapshot(exchange + margin together)
668
+ # [
669
+ # 0,
670
+ # "ws",
671
+ # [
672
+ # [
673
+ # "exchange",
674
+ # "LTC",
675
+ # 0.05479727,
676
+ # 0,
677
+ # null,
678
+ # "Trading fees for 0.05 LTC(LTCUST) @ 51.872 on BFX(0.2%)",
679
+ # null,
680
+ # ]
681
+ # [
682
+ # "margin",
683
+ # "USTF0",
684
+ # 11.960650700086292,
685
+ # 0,
686
+ # null,
687
+ # "Trading fees for 0.1 LTCF0(LTCF0:USTF0) @ 51.844 on BFX(0.065%)",
688
+ # null,
689
+ # ],
690
+ # ],
691
+ # ]
348
692
  #
349
- # {"event": "heartbeat"}
693
+ # spot
694
+ # [
695
+ # 0,
696
+ # "wu",
697
+ # [
698
+ # "exchange",
699
+ # "LTC", # currency
700
+ # 0.06729727, # wallet balance
701
+ # 0, # unsettled balance
702
+ # 0.06729727, # available balance might be null
703
+ # "Exchange 0.4 LTC for UST @ 65.075",
704
+ # {
705
+ # "reason": "TRADE",
706
+ # "order_id": 96596397973,
707
+ # "order_id_oppo": 96596632735,
708
+ # "trade_price": "65.075",
709
+ # "trade_amount": "-0.4",
710
+ # "order_cid": 1654636218766,
711
+ # "order_gid": null
712
+ # }
713
+ # ]
714
+ # ]
350
715
  #
351
- event = self.safe_string(message, 'event')
352
- client.resolve(message, event)
716
+ # margin
717
+ #
718
+ # [
719
+ # "margin",
720
+ # "USTF0",
721
+ # 11.960650700086292, # total
722
+ # 0,
723
+ # 6.776250700086292, # available
724
+ # "Trading fees for 0.1 LTCF0(LTCF0:USTF0) @ 51.844 on BFX(0.065%)",
725
+ # null
726
+ # ]
727
+ #
728
+ updateType = self.safe_value(message, 1)
729
+ data = None
730
+ if updateType == 'ws':
731
+ data = self.safe_value(message, 2)
732
+ else:
733
+ data = [self.safe_value(message, 2)]
734
+ updatedTypes: dict = {}
735
+ for i in range(0, len(data)):
736
+ rawBalance = data[i]
737
+ currencyId = self.safe_string(rawBalance, 1)
738
+ code = self.safe_currency_code(currencyId)
739
+ balance = self.parse_ws_balance(rawBalance)
740
+ balanceType = self.safe_string(rawBalance, 0)
741
+ oldBalance = self.safe_value(self.balance, balanceType, {})
742
+ oldBalance[code] = balance
743
+ oldBalance['info'] = message
744
+ self.balance[balanceType] = self.safe_balance(oldBalance)
745
+ updatedTypes[balanceType] = True
746
+ updatesKeys = list(updatedTypes.keys())
747
+ for i in range(0, len(updatesKeys)):
748
+ type = updatesKeys[i]
749
+ messageHash = 'balance:' + type
750
+ client.resolve(self.balance[type], messageHash)
353
751
 
354
- def handle_system_status(self, client: Client, message):
752
+ def parse_ws_balance(self, balance):
355
753
  #
356
- # todo: answer the question whether handleSystemStatus should be renamed
357
- # and unified for any usage pattern that
358
- # involves system status and maintenance updates
754
+ # [
755
+ # "exchange",
756
+ # "LTC",
757
+ # 0.05479727, # balance
758
+ # 0,
759
+ # null, # available null if not calculated yet
760
+ # "Trading fees for 0.05 LTC(LTCUST) @ 51.872 on BFX(0.2%)",
761
+ # null,
762
+ # ]
763
+ #
764
+ totalBalance = self.safe_string(balance, 2)
765
+ availableBalance = self.safe_string(balance, 4)
766
+ account = self.account()
767
+ if availableBalance is not None:
768
+ account['free'] = availableBalance
769
+ account['total'] = totalBalance
770
+ return account
771
+
772
+ def handle_system_status(self, client: Client, message):
359
773
  #
360
774
  # {
361
775
  # "event": "info",
@@ -386,46 +800,38 @@ class bitfinex(ccxt.async_support.bitfinex):
386
800
  async def authenticate(self, params={}):
387
801
  url = self.urls['api']['ws']['private']
388
802
  client = self.client(url)
389
- future = client.future('authenticated')
390
- method = 'auth'
391
- authenticated = self.safe_value(client.subscriptions, method)
803
+ messageHash = 'authenticated'
804
+ future = client.future(messageHash)
805
+ authenticated = self.safe_value(client.subscriptions, messageHash)
392
806
  if authenticated is None:
393
807
  nonce = self.milliseconds()
394
808
  payload = 'AUTH' + str(nonce)
395
809
  signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha384, 'hex')
396
- request = {
810
+ event = 'auth'
811
+ request: dict = {
397
812
  'apiKey': self.apiKey,
398
813
  'authSig': signature,
399
814
  'authNonce': nonce,
400
815
  'authPayload': payload,
401
- 'event': method,
402
- 'filter': [
403
- 'trading',
404
- 'wallet',
405
- ],
816
+ 'event': event,
406
817
  }
407
- self.spawn(self.watch, url, method, request, 1)
818
+ message = self.extend(request, params)
819
+ self.watch(url, messageHash, message, messageHash)
408
820
  return await future
409
821
 
410
822
  def handle_authentication_message(self, client: Client, message):
823
+ messageHash = 'authenticated'
411
824
  status = self.safe_string(message, 'status')
412
825
  if status == 'OK':
413
826
  # we resolve the future here permanently so authentication only happens once
414
- future = self.safe_value(client.futures, 'authenticated')
827
+ future = self.safe_value(client.futures, messageHash)
415
828
  future.resolve(True)
416
829
  else:
417
830
  error = AuthenticationError(self.json(message))
418
- client.reject(error, 'authenticated')
831
+ client.reject(error, messageHash)
419
832
  # allows further authentication attempts
420
- method = self.safe_string(message, 'event')
421
- if method in client.subscriptions:
422
- del client.subscriptions[method]
423
-
424
- async def watch_order(self, id, symbol: Str = None, params={}):
425
- await self.load_markets()
426
- url = self.urls['api']['ws']['private']
427
- await self.authenticate()
428
- return await self.watch(url, id, None, 1)
833
+ if messageHash in client.subscriptions:
834
+ del client.subscriptions[messageHash]
429
835
 
430
836
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
431
837
  """
@@ -437,115 +843,161 @@ class bitfinex(ccxt.async_support.bitfinex):
437
843
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
438
844
  """
439
845
  await self.load_markets()
440
- await self.authenticate()
846
+ messageHash = 'orders'
441
847
  if symbol is not None:
442
- symbol = self.symbol(symbol)
443
- url = self.urls['api']['ws']['private']
444
- orders = await self.watch(url, 'os', None, 1)
848
+ market = self.market(symbol)
849
+ messageHash += ':' + market['id']
850
+ orders = await self.subscribe_private(messageHash)
445
851
  if self.newUpdates:
446
852
  limit = orders.getLimit(symbol, limit)
447
853
  return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
448
854
 
449
855
  def handle_orders(self, client: Client, message, subscription):
450
856
  #
451
- # order snapshot
452
- #
453
- # [
454
- # 0,
455
- # "os",
456
- # [
457
- # [
458
- # 45287766631,
459
- # "ETHUST",
460
- # -0.07,
461
- # -0.07,
462
- # "EXCHANGE LIMIT",
463
- # "ACTIVE",
464
- # 210,
465
- # 0,
466
- # "2020-05-16T13:17:46Z",
467
- # 0,
468
- # 0,
469
- # 0
470
- # ]
471
- # ]
472
- # ]
473
- #
474
- # order cancel
475
- #
476
- # [
477
- # 0,
478
- # "oc",
479
- # [
480
- # 45287766631,
481
- # "ETHUST",
482
- # -0.07,
483
- # -0.07,
484
- # "EXCHANGE LIMIT",
485
- # "CANCELED",
486
- # 210,
487
- # 0,
488
- # "2020-05-16T13:17:46Z",
489
- # 0,
490
- # 0,
491
- # 0,
492
- # ]
493
- # ]
857
+ # limit order
858
+ # [
859
+ # 0,
860
+ # "on", # ou or oc
861
+ # [
862
+ # 96923856256, # order id
863
+ # null, # gid
864
+ # 1655029337026, # cid
865
+ # "tLTCUST", # symbol
866
+ # 1655029337027, # created timestamp
867
+ # 1655029337029, # updated timestamp
868
+ # 0.1, # amount
869
+ # 0.1, # amount_orig
870
+ # "EXCHANGE LIMIT", # order type
871
+ # null, # type_prev
872
+ # null, # mts_tif
873
+ # null, # placeholder
874
+ # 0, # flags
875
+ # "ACTIVE", # status
876
+ # null,
877
+ # null,
878
+ # 30, # price
879
+ # 0, # price average
880
+ # 0, # price_trailling
881
+ # 0, # price_aux_limit
882
+ # null,
883
+ # null,
884
+ # null,
885
+ # 0, # notify
886
+ # 0,
887
+ # null,
888
+ # null,
889
+ # null,
890
+ # "BFX",
891
+ # null,
892
+ # null,
893
+ # ]
894
+ # ]
494
895
  #
495
896
  data = self.safe_value(message, 2, [])
496
897
  messageType = self.safe_string(message, 1)
898
+ if self.orders is None:
899
+ limit = self.safe_integer(self.options, 'ordersLimit', 1000)
900
+ self.orders = ArrayCacheBySymbolById(limit)
901
+ orders = self.orders
902
+ symbolIds: dict = {}
497
903
  if messageType == 'os':
904
+ snapshotLength = len(data)
905
+ if snapshotLength == 0:
906
+ return
498
907
  for i in range(0, len(data)):
499
908
  value = data[i]
500
- self.handle_order(client, value)
909
+ parsed = self.parse_ws_order(value)
910
+ symbol = parsed['symbol']
911
+ symbolIds[symbol] = True
912
+ orders.append(parsed)
501
913
  else:
502
- self.handle_order(client, data)
503
- if self.orders is not None:
504
- client.resolve(self.orders, 'os')
914
+ parsed = self.parse_ws_order(data)
915
+ orders.append(parsed)
916
+ symbol = parsed['symbol']
917
+ symbolIds[symbol] = True
918
+ name = 'orders'
919
+ client.resolve(self.orders, name)
920
+ keys = list(symbolIds.keys())
921
+ for i in range(0, len(keys)):
922
+ symbol = keys[i]
923
+ market = self.market(symbol)
924
+ messageHash = name + ':' + market['id']
925
+ client.resolve(self.orders, messageHash)
505
926
 
506
927
  def parse_ws_order_status(self, status):
507
- statuses = {
928
+ statuses: dict = {
508
929
  'ACTIVE': 'open',
509
930
  'CANCELED': 'canceled',
931
+ 'EXECUTED': 'closed',
932
+ 'PARTIALLY': 'open',
510
933
  }
511
934
  return self.safe_string(statuses, status, status)
512
935
 
513
- def handle_order(self, client: Client, order):
514
- # [45287766631,
515
- # "ETHUST",
516
- # -0.07,
517
- # -0.07,
518
- # "EXCHANGE LIMIT",
519
- # "CANCELED",
520
- # 210,
521
- # 0,
522
- # "2020-05-16T13:17:46Z",
523
- # 0,
524
- # 0,
525
- # 0]
936
+ def parse_ws_order(self, order, market=None):
937
+ #
938
+ # [
939
+ # 97084883506, # order id
940
+ # null,
941
+ # 1655110144596, # clientOrderId
942
+ # "tLTCUST", # symbol
943
+ # 1655110144596, # created timestamp
944
+ # 1655110144598, # updated timestamp
945
+ # 0, # amount
946
+ # 0.1, # amount_orig negative if sell order
947
+ # "EXCHANGE MARKET", # type
948
+ # null,
949
+ # null,
950
+ # null,
951
+ # 0,
952
+ # "EXECUTED @ 42.821(0.1)", # status
953
+ # null,
954
+ # null,
955
+ # 42.799, # price
956
+ # 42.821, # price average
957
+ # 0, # price trailling
958
+ # 0, # price_aux_limit
959
+ # null,
960
+ # null,
961
+ # null,
962
+ # 0,
963
+ # 0,
964
+ # null,
965
+ # null,
966
+ # null,
967
+ # "BFX",
968
+ # null,
969
+ # null,
970
+ # {}
971
+ # ]
972
+ #
526
973
  id = self.safe_string(order, 0)
527
- marketId = self.safe_string(order, 1)
974
+ clientOrderId = self.safe_string(order, 1)
975
+ marketId = self.safe_string(order, 3)
528
976
  symbol = self.safe_symbol(marketId)
529
- amount = self.safe_string(order, 2)
530
- remaining = self.safe_string(order, 3)
977
+ market = self.safe_market(symbol)
978
+ amount = self.safe_string(order, 7)
531
979
  side = 'buy'
532
980
  if Precise.string_lt(amount, '0'):
533
981
  amount = Precise.string_abs(amount)
534
- remaining = Precise.string_abs(remaining)
535
982
  side = 'sell'
536
- type = self.safe_string(order, 4)
983
+ remaining = Precise.string_abs(self.safe_string(order, 6))
984
+ type = self.safe_string(order, 8)
537
985
  if type.find('LIMIT') > -1:
538
986
  type = 'limit'
539
987
  elif type.find('MARKET') > -1:
540
988
  type = 'market'
541
- status = self.parse_ws_order_status(self.safe_string(order, 5))
542
- price = self.safe_string(order, 6)
543
- rawDatetime = self.safe_string(order, 8)
544
- timestamp = self.parse8601(rawDatetime)
545
- parsed = self.safe_order({
989
+ rawState = self.safe_string(order, 13)
990
+ stateParts = rawState.split(' ')
991
+ trimmedStatus = self.safe_string(stateParts, 0)
992
+ status = self.parse_ws_order_status(trimmedStatus)
993
+ price = self.safe_string(order, 16)
994
+ timestamp = self.safe_integer_2(order, 5, 4)
995
+ average = self.safe_string(order, 17)
996
+ stopPrice = self.omit_zero(self.safe_string(order, 18))
997
+ return self.safe_order({
546
998
  'info': order,
547
999
  'id': id,
548
- 'clientOrderId': None,
1000
+ 'clientOrderId': clientOrderId,
549
1001
  'timestamp': timestamp,
550
1002
  'datetime': self.iso8601(timestamp),
551
1003
  'lastTradeTimestamp': None,
@@ -553,9 +1005,9 @@ class bitfinex(ccxt.async_support.bitfinex):
553
1005
  'type': type,
554
1006
  'side': side,
555
1007
  'price': price,
556
- 'stopPrice': None,
557
- 'triggerPrice': None,
558
- 'average': None,
1008
+ 'stopPrice': stopPrice,
1009
+ 'triggerPrice': stopPrice,
1010
+ 'average': average,
559
1011
  'amount': amount,
560
1012
  'remaining': remaining,
561
1013
  'filled': None,
@@ -563,56 +1015,69 @@ class bitfinex(ccxt.async_support.bitfinex):
563
1015
  'fee': None,
564
1016
  'cost': None,
565
1017
  'trades': None,
566
- })
567
- if self.orders is None:
568
- limit = self.safe_integer(self.options, 'ordersLimit', 1000)
569
- self.orders = ArrayCacheBySymbolById(limit)
570
- orders = self.orders
571
- orders.append(parsed)
572
- client.resolve(parsed, id)
573
- return parsed
1018
+ }, market)
574
1019
 
575
1020
  def handle_message(self, client: Client, message):
1021
+ channelId = self.safe_string(message, 0)
1022
+ #
1023
+ # [
1024
+ # 1231,
1025
+ # "hb",
1026
+ # ]
1027
+ #
1028
+ # auth message
1029
+ # {
1030
+ # "event": "auth",
1031
+ # "status": "OK",
1032
+ # "chanId": 0,
1033
+ # "userId": 3159883,
1034
+ # "auth_id": "ac7108e7-2f26-424d-9982-c24700dc02ca",
1035
+ # "caps": {
1036
+ # "orders": {read: 1, write: 1},
1037
+ # "account": {read: 1, write: 1},
1038
+ # "funding": {read: 1, write: 1},
1039
+ # "history": {read: 1, write: 0},
1040
+ # "wallets": {read: 1, write: 1},
1041
+ # "withdraw": {read: 0, write: 1},
1042
+ # "positions": {read: 1, write: 1},
1043
+ # "ui_withdraw": {read: 0, write: 0}
1044
+ # }
1045
+ # }
1046
+ #
576
1047
  if isinstance(message, list):
577
- channelId = self.safe_string(message, 0)
578
- #
579
- # [
580
- # 1231,
581
- # "hb",
582
- # ]
583
- #
584
1048
  if message[1] == 'hb':
585
1049
  return # skip heartbeats within subscription channels for now
586
1050
  subscription = self.safe_value(client.subscriptions, channelId, {})
587
1051
  channel = self.safe_string(subscription, 'channel')
588
1052
  name = self.safe_string(message, 1)
589
- methods = {
1053
+ publicMethods: dict = {
590
1054
  'book': self.handle_order_book,
591
- # 'ohlc': self.handleOHLCV,
1055
+ 'cs': self.handle_checksum,
1056
+ 'candles': self.handle_ohlcv,
592
1057
  'ticker': self.handle_ticker,
593
1058
  'trades': self.handle_trades,
1059
+ }
1060
+ privateMethods: dict = {
594
1061
  'os': self.handle_orders,
1062
+ 'ou': self.handle_orders,
595
1063
  'on': self.handle_orders,
596
1064
  'oc': self.handle_orders,
1065
+ 'wu': self.handle_balance,
1066
+ 'ws': self.handle_balance,
1067
+ 'tu': self.handle_my_trade,
597
1068
  }
598
- method = self.safe_value_2(methods, channel, name)
1069
+ method = None
1070
+ if channelId == '0':
1071
+ method = self.safe_value(privateMethods, name)
1072
+ else:
1073
+ method = self.safe_value_2(publicMethods, name, channel)
599
1074
  if method is not None:
600
1075
  method(client, message, subscription)
601
1076
  else:
602
- # todo add bitfinex handleErrorMessage
603
- #
604
- # {
605
- # "event": "info",
606
- # "version": 2,
607
- # "serverId": "e293377e-7bb7-427e-b28c-5db045b2c1d1",
608
- # "platform": {status: 1}, # 1 for operative, 0 for maintenance
609
- # }
610
- #
611
1077
  event = self.safe_string(message, 'event')
612
1078
  if event is not None:
613
- methods = {
1079
+ methods: dict = {
614
1080
  'info': self.handle_system_status,
615
- # 'book': 'handleOrderBook',
616
1081
  'subscribed': self.handle_subscription_status,
617
1082
  'auth': self.handle_authentication_message,
618
1083
  }