ccxt-ir 4.3.46.0.3__py2.py3-none-any.whl → 4.5.0__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 (529) hide show
  1. ccxt/__init__.py +39 -35
  2. ccxt/abantether.py +8 -8
  3. ccxt/abstract/alpaca.py +4 -0
  4. ccxt/abstract/apex.py +31 -0
  5. ccxt/abstract/bigone.py +1 -1
  6. ccxt/abstract/binance.py +106 -48
  7. ccxt/abstract/binancecoinm.py +106 -48
  8. ccxt/abstract/binanceus.py +141 -83
  9. ccxt/abstract/binanceusdm.py +106 -48
  10. ccxt/abstract/bingx.py +50 -1
  11. ccxt/abstract/bitbank.py +5 -0
  12. ccxt/abstract/bitfinex.py +136 -65
  13. ccxt/abstract/bitflyer.py +1 -0
  14. ccxt/abstract/bitget.py +67 -0
  15. ccxt/abstract/bitmart.py +19 -1
  16. ccxt/abstract/bitopro.py +1 -0
  17. ccxt/abstract/bitrue.py +68 -68
  18. ccxt/abstract/bitstamp.py +1 -0
  19. ccxt/abstract/blofin.py +30 -0
  20. ccxt/abstract/btcbox.py +2 -0
  21. ccxt/abstract/bybit.py +28 -13
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbaseexchange.py +1 -0
  24. ccxt/abstract/coinbaseinternational.py +1 -1
  25. ccxt/abstract/cryptocom.py +16 -0
  26. ccxt/abstract/cryptomus.py +20 -0
  27. ccxt/abstract/defx.py +69 -0
  28. ccxt/abstract/deribit.py +1 -0
  29. ccxt/abstract/derive.py +117 -0
  30. ccxt/abstract/digifinex.py +1 -0
  31. ccxt/abstract/ellipx.py +25 -0
  32. ccxt/abstract/foxbit.py +26 -0
  33. ccxt/abstract/gate.py +19 -0
  34. ccxt/abstract/gateio.py +19 -0
  35. ccxt/abstract/gemini.py +1 -0
  36. ccxt/abstract/hibachi.py +26 -0
  37. ccxt/abstract/hyperliquid.py +1 -1
  38. ccxt/abstract/independentreserve.py +6 -0
  39. ccxt/abstract/kraken.py +1 -0
  40. ccxt/abstract/krakenfutures.py +4 -0
  41. ccxt/abstract/kucoin.py +10 -0
  42. ccxt/abstract/kucoinfutures.py +18 -0
  43. ccxt/abstract/lbank.py +2 -1
  44. ccxt/abstract/luno.py +1 -0
  45. ccxt/abstract/mexc.py +2 -0
  46. ccxt/abstract/modetrade.py +119 -0
  47. ccxt/abstract/myokx.py +349 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +25 -0
  50. ccxt/abstract/okxus.py +349 -0
  51. ccxt/abstract/onetrading.py +0 -12
  52. ccxt/abstract/paradex.py +23 -0
  53. ccxt/abstract/phemex.py +2 -0
  54. ccxt/abstract/poloniex.py +36 -0
  55. ccxt/abstract/tradeogre.py +3 -1
  56. ccxt/abstract/upbit.py +51 -34
  57. ccxt/abstract/whitebit.py +16 -0
  58. ccxt/abstract/woo.py +64 -6
  59. ccxt/abstract/xt.py +10 -5
  60. ccxt/afratether.py +7 -7
  61. ccxt/alpaca.py +828 -51
  62. ccxt/apex.py +1875 -0
  63. ccxt/arzinja.py +7 -7
  64. ccxt/arzplus.py +9 -9
  65. ccxt/ascendex.py +501 -306
  66. ccxt/async_support/__init__.py +39 -35
  67. ccxt/async_support/abantether.py +8 -8
  68. ccxt/async_support/afratether.py +9 -9
  69. ccxt/async_support/alpaca.py +828 -51
  70. ccxt/async_support/apex.py +1875 -0
  71. ccxt/async_support/arzinja.py +10 -10
  72. ccxt/async_support/arzplus.py +12 -12
  73. ccxt/async_support/ascendex.py +502 -306
  74. ccxt/async_support/base/exchange.py +303 -89
  75. ccxt/async_support/base/ws/cache.py +9 -3
  76. ccxt/async_support/base/ws/client.py +173 -38
  77. ccxt/async_support/base/ws/future.py +25 -37
  78. ccxt/async_support/bequant.py +5 -3
  79. ccxt/async_support/bigone.py +279 -144
  80. ccxt/async_support/binance.py +2347 -1158
  81. ccxt/async_support/binancecoinm.py +9 -3
  82. ccxt/async_support/binanceus.py +17 -3
  83. ccxt/async_support/binanceusdm.py +9 -4
  84. ccxt/async_support/bingx.py +2962 -920
  85. ccxt/async_support/bit2c.py +147 -27
  86. ccxt/async_support/bitbank.py +151 -23
  87. ccxt/async_support/bitbns.py +104 -30
  88. ccxt/async_support/bitfinex.py +3291 -1113
  89. ccxt/async_support/bitflyer.py +202 -27
  90. ccxt/async_support/bitget.py +3683 -1538
  91. ccxt/async_support/bithumb.py +195 -38
  92. ccxt/async_support/bitimen.py +12 -12
  93. ccxt/async_support/bitir.py +38 -38
  94. ccxt/async_support/bitmart.py +1288 -350
  95. ccxt/async_support/bitmex.py +260 -75
  96. ccxt/async_support/bitopro.py +262 -62
  97. ccxt/async_support/bitpin.py +17 -16
  98. ccxt/async_support/bitrue.py +459 -290
  99. ccxt/async_support/bitso.py +199 -54
  100. ccxt/async_support/bitstamp.py +230 -96
  101. ccxt/async_support/bitteam.py +167 -25
  102. ccxt/async_support/{huobijp.py → bittrade.py} +158 -30
  103. ccxt/async_support/bitvavo.py +213 -49
  104. ccxt/async_support/blockchaincom.py +160 -46
  105. ccxt/async_support/blofin.py +502 -120
  106. ccxt/async_support/btcalpha.py +169 -31
  107. ccxt/async_support/btcbox.py +292 -23
  108. ccxt/async_support/btcmarkets.py +211 -58
  109. ccxt/async_support/btcturk.py +161 -38
  110. ccxt/async_support/bybit.py +1775 -1030
  111. ccxt/async_support/cex.py +1440 -1303
  112. ccxt/async_support/coinbase.py +724 -212
  113. ccxt/async_support/coinbaseadvanced.py +2 -1
  114. ccxt/async_support/coinbaseexchange.py +388 -89
  115. ccxt/async_support/coinbaseinternational.py +412 -57
  116. ccxt/async_support/coincatch.py +177 -78
  117. ccxt/async_support/coincheck.py +135 -19
  118. ccxt/async_support/coinex.py +606 -232
  119. ccxt/async_support/coinmate.py +189 -63
  120. ccxt/async_support/coinmetro.py +195 -54
  121. ccxt/async_support/coinone.py +158 -51
  122. ccxt/async_support/coinsph.py +336 -61
  123. ccxt/async_support/coinspot.py +151 -52
  124. ccxt/async_support/cryptocom.py +661 -111
  125. ccxt/async_support/cryptomus.py +1137 -0
  126. ccxt/async_support/defx.py +2071 -0
  127. ccxt/async_support/delta.py +299 -99
  128. ccxt/async_support/deribit.py +348 -126
  129. ccxt/async_support/derive.py +2572 -0
  130. ccxt/async_support/digifinex.py +430 -214
  131. ccxt/async_support/ellipx.py +2029 -0
  132. ccxt/async_support/eterex.py +10 -10
  133. ccxt/async_support/excoino.py +31 -31
  134. ccxt/async_support/exir.py +14 -14
  135. ccxt/async_support/exmo.py +344 -131
  136. ccxt/async_support/exnovin.py +10 -10
  137. ccxt/async_support/farhadexchange.py +12 -12
  138. ccxt/async_support/fmfwio.py +2 -1
  139. ccxt/async_support/foxbit.py +1935 -0
  140. ccxt/async_support/gate.py +1351 -529
  141. ccxt/async_support/gateio.py +2 -1
  142. ccxt/async_support/gemini.py +144 -39
  143. ccxt/async_support/hashkey.py +152 -109
  144. ccxt/async_support/hibachi.py +2080 -0
  145. ccxt/async_support/hitbtc.py +395 -167
  146. ccxt/async_support/hitobit.py +12 -12
  147. ccxt/async_support/hollaex.py +307 -119
  148. ccxt/async_support/htx.py +851 -383
  149. ccxt/async_support/huobi.py +2 -1
  150. ccxt/async_support/hyperliquid.py +1848 -536
  151. ccxt/async_support/independentreserve.py +288 -15
  152. ccxt/async_support/indodax.py +190 -33
  153. ccxt/async_support/jibitex.py +12 -12
  154. ccxt/async_support/kraken.py +795 -351
  155. ccxt/async_support/krakenfutures.py +214 -62
  156. ccxt/async_support/kucoin.py +715 -396
  157. ccxt/async_support/kucoinfutures.py +652 -89
  158. ccxt/async_support/latoken.py +217 -113
  159. ccxt/async_support/lbank.py +425 -97
  160. ccxt/async_support/luno.py +382 -35
  161. ccxt/async_support/mercado.py +113 -6
  162. ccxt/async_support/mexc.py +874 -437
  163. ccxt/async_support/modetrade.py +2818 -0
  164. ccxt/async_support/myokx.py +54 -0
  165. ccxt/async_support/ndax.py +221 -64
  166. ccxt/async_support/nobitex.py +31 -37
  167. ccxt/async_support/novadax.py +190 -34
  168. ccxt/async_support/oceanex.py +217 -28
  169. ccxt/async_support/okcoin.py +253 -145
  170. ccxt/async_support/okexchange.py +11 -11
  171. ccxt/async_support/okx.py +1088 -351
  172. ccxt/async_support/okxus.py +54 -0
  173. ccxt/async_support/ompfinex.py +25 -24
  174. ccxt/async_support/onetrading.py +213 -392
  175. ccxt/async_support/oxfun.py +245 -166
  176. ccxt/async_support/p2b.py +151 -29
  177. ccxt/async_support/paradex.py +562 -49
  178. ccxt/async_support/paymium.py +82 -19
  179. ccxt/async_support/phemex.py +713 -172
  180. ccxt/async_support/poloniex.py +1602 -283
  181. ccxt/async_support/probit.py +224 -95
  182. ccxt/async_support/ramzinex.py +30 -27
  183. ccxt/async_support/sarmayex.py +9 -9
  184. ccxt/async_support/sarrafex.py +13 -13
  185. ccxt/async_support/tabdeal.py +14 -13
  186. ccxt/async_support/tetherland.py +9 -9
  187. ccxt/async_support/timex.py +210 -51
  188. ccxt/async_support/tokocrypto.py +167 -47
  189. ccxt/async_support/tradeogre.py +266 -31
  190. ccxt/async_support/twox.py +9 -9
  191. ccxt/async_support/ubitex.py +12 -12
  192. ccxt/async_support/upbit.py +568 -165
  193. ccxt/async_support/vertex.py +160 -32
  194. ccxt/async_support/wallex.py +12 -12
  195. ccxt/async_support/wavesexchange.py +165 -30
  196. ccxt/async_support/whitebit.py +975 -127
  197. ccxt/async_support/woo.py +1918 -1016
  198. ccxt/async_support/woofipro.py +433 -141
  199. ccxt/async_support/xt.py +649 -193
  200. ccxt/async_support/yobit.py +195 -70
  201. ccxt/async_support/zaif.py +91 -15
  202. ccxt/async_support/zonda.py +151 -36
  203. ccxt/base/decimal_to_precision.py +14 -10
  204. ccxt/base/errors.py +49 -18
  205. ccxt/base/exchange.py +1556 -450
  206. ccxt/base/precise.py +10 -0
  207. ccxt/base/types.py +114 -6
  208. ccxt/bequant.py +5 -3
  209. ccxt/bigone.py +279 -144
  210. ccxt/binance.py +2347 -1158
  211. ccxt/binancecoinm.py +9 -3
  212. ccxt/binanceus.py +17 -3
  213. ccxt/binanceusdm.py +9 -4
  214. ccxt/bingx.py +2962 -920
  215. ccxt/bit2c.py +147 -27
  216. ccxt/bitbank.py +151 -23
  217. ccxt/bitbns.py +104 -30
  218. ccxt/bitfinex.py +3290 -1113
  219. ccxt/bitflyer.py +202 -27
  220. ccxt/bitget.py +3683 -1538
  221. ccxt/bithumb.py +194 -38
  222. ccxt/bitimen.py +9 -9
  223. ccxt/bitir.py +35 -35
  224. ccxt/bitmart.py +1288 -350
  225. ccxt/bitmex.py +260 -75
  226. ccxt/bitopro.py +262 -62
  227. ccxt/bitpin.py +15 -14
  228. ccxt/bitrue.py +459 -290
  229. ccxt/bitso.py +199 -54
  230. ccxt/bitstamp.py +230 -96
  231. ccxt/bitteam.py +167 -25
  232. ccxt/{huobijp.py → bittrade.py} +158 -30
  233. ccxt/bitvavo.py +213 -49
  234. ccxt/blockchaincom.py +160 -46
  235. ccxt/blofin.py +502 -120
  236. ccxt/btcalpha.py +169 -31
  237. ccxt/btcbox.py +291 -23
  238. ccxt/btcmarkets.py +211 -58
  239. ccxt/btcturk.py +161 -38
  240. ccxt/bybit.py +1775 -1030
  241. ccxt/cex.py +1439 -1303
  242. ccxt/coinbase.py +724 -212
  243. ccxt/coinbaseadvanced.py +2 -1
  244. ccxt/coinbaseexchange.py +388 -89
  245. ccxt/coinbaseinternational.py +412 -57
  246. ccxt/coincatch.py +177 -78
  247. ccxt/coincheck.py +135 -19
  248. ccxt/coinex.py +606 -232
  249. ccxt/coinmate.py +189 -63
  250. ccxt/coinmetro.py +194 -54
  251. ccxt/coinone.py +158 -51
  252. ccxt/coinsph.py +336 -61
  253. ccxt/coinspot.py +151 -52
  254. ccxt/cryptocom.py +661 -111
  255. ccxt/cryptomus.py +1137 -0
  256. ccxt/defx.py +2070 -0
  257. ccxt/delta.py +299 -99
  258. ccxt/deribit.py +348 -126
  259. ccxt/derive.py +2571 -0
  260. ccxt/digifinex.py +430 -214
  261. ccxt/ellipx.py +2029 -0
  262. ccxt/eterex.py +7 -7
  263. ccxt/excoino.py +29 -29
  264. ccxt/exir.py +11 -11
  265. ccxt/exmo.py +343 -131
  266. ccxt/exnovin.py +8 -8
  267. ccxt/farhadexchange.py +10 -10
  268. ccxt/fmfwio.py +2 -1
  269. ccxt/foxbit.py +1935 -0
  270. ccxt/gate.py +1351 -529
  271. ccxt/gateio.py +2 -1
  272. ccxt/gemini.py +144 -39
  273. ccxt/hashkey.py +152 -109
  274. ccxt/hibachi.py +2079 -0
  275. ccxt/hitbtc.py +395 -167
  276. ccxt/hitobit.py +9 -9
  277. ccxt/hollaex.py +307 -119
  278. ccxt/htx.py +851 -383
  279. ccxt/huobi.py +2 -1
  280. ccxt/hyperliquid.py +1848 -536
  281. ccxt/independentreserve.py +287 -15
  282. ccxt/indodax.py +190 -33
  283. ccxt/jibitex.py +9 -9
  284. ccxt/kraken.py +794 -351
  285. ccxt/krakenfutures.py +214 -62
  286. ccxt/kucoin.py +715 -396
  287. ccxt/kucoinfutures.py +652 -89
  288. ccxt/latoken.py +217 -113
  289. ccxt/lbank.py +425 -97
  290. ccxt/luno.py +382 -35
  291. ccxt/mercado.py +113 -6
  292. ccxt/mexc.py +873 -437
  293. ccxt/modetrade.py +2818 -0
  294. ccxt/myokx.py +54 -0
  295. ccxt/ndax.py +221 -64
  296. ccxt/nobitex.py +29 -35
  297. ccxt/novadax.py +190 -34
  298. ccxt/oceanex.py +217 -28
  299. ccxt/okcoin.py +253 -145
  300. ccxt/okexchange.py +9 -9
  301. ccxt/okx.py +1088 -351
  302. ccxt/okxus.py +54 -0
  303. ccxt/ompfinex.py +22 -21
  304. ccxt/onetrading.py +213 -392
  305. ccxt/oxfun.py +245 -166
  306. ccxt/p2b.py +151 -29
  307. ccxt/paradex.py +562 -49
  308. ccxt/paymium.py +82 -19
  309. ccxt/phemex.py +712 -172
  310. ccxt/poloniex.py +1601 -283
  311. ccxt/pro/__init__.py +76 -17
  312. ccxt/pro/alpaca.py +21 -6
  313. ccxt/pro/apex.py +984 -0
  314. ccxt/pro/ascendex.py +58 -10
  315. ccxt/pro/bequant.py +6 -1
  316. ccxt/pro/binance.py +728 -156
  317. ccxt/pro/binancecoinm.py +6 -2
  318. ccxt/pro/binanceus.py +8 -4
  319. ccxt/pro/binanceusdm.py +7 -2
  320. ccxt/pro/bingx.py +333 -142
  321. ccxt/pro/bitfinex.py +727 -262
  322. ccxt/pro/bitget.py +570 -79
  323. ccxt/pro/bithumb.py +20 -6
  324. ccxt/pro/bitmart.py +216 -87
  325. ccxt/pro/bitmex.py +47 -9
  326. ccxt/pro/bitopro.py +26 -14
  327. ccxt/pro/bitrue.py +22 -22
  328. ccxt/pro/bitstamp.py +54 -21
  329. ccxt/pro/{huobijp.py → bittrade.py} +7 -6
  330. ccxt/pro/bitvavo.py +191 -67
  331. ccxt/pro/blockchaincom.py +21 -8
  332. ccxt/pro/blofin.py +9 -1
  333. ccxt/pro/bybit.py +632 -245
  334. ccxt/pro/cex.py +59 -24
  335. ccxt/pro/coinbase.py +102 -73
  336. ccxt/pro/coinbaseadvanced.py +2 -1
  337. ccxt/pro/coinbaseexchange.py +8 -8
  338. ccxt/pro/coinbaseinternational.py +181 -25
  339. ccxt/pro/coincatch.py +6 -7
  340. ccxt/pro/coincheck.py +11 -6
  341. ccxt/pro/coinex.py +967 -665
  342. ccxt/pro/coinone.py +16 -9
  343. ccxt/pro/cryptocom.py +448 -45
  344. ccxt/pro/defx.py +831 -0
  345. ccxt/pro/deribit.py +150 -14
  346. ccxt/pro/derive.py +704 -0
  347. ccxt/pro/exmo.py +239 -6
  348. ccxt/pro/gate.py +623 -65
  349. ccxt/pro/gateio.py +2 -1
  350. ccxt/pro/gemini.py +27 -11
  351. ccxt/pro/hashkey.py +2 -2
  352. ccxt/pro/hitbtc.py +196 -91
  353. ccxt/pro/hollaex.py +23 -7
  354. ccxt/pro/htx.py +51 -14
  355. ccxt/pro/huobi.py +2 -1
  356. ccxt/pro/hyperliquid.py +591 -27
  357. ccxt/pro/independentreserve.py +9 -6
  358. ccxt/pro/kraken.py +640 -320
  359. ccxt/pro/krakenfutures.py +62 -35
  360. ccxt/pro/kucoin.py +267 -46
  361. ccxt/pro/kucoinfutures.py +165 -21
  362. ccxt/pro/lbank.py +102 -21
  363. ccxt/pro/luno.py +12 -8
  364. ccxt/pro/mexc.py +877 -111
  365. ccxt/pro/modetrade.py +1271 -0
  366. ccxt/pro/myokx.py +38 -0
  367. ccxt/pro/ndax.py +15 -2
  368. ccxt/pro/okcoin.py +23 -4
  369. ccxt/pro/okx.py +573 -98
  370. ccxt/pro/okxus.py +38 -0
  371. ccxt/pro/onetrading.py +30 -13
  372. ccxt/pro/oxfun.py +131 -27
  373. ccxt/pro/p2b.py +88 -22
  374. ccxt/pro/paradex.py +3 -3
  375. ccxt/pro/phemex.py +75 -21
  376. ccxt/pro/poloniex.py +124 -41
  377. ccxt/pro/probit.py +87 -80
  378. ccxt/pro/tradeogre.py +272 -0
  379. ccxt/pro/upbit.py +152 -12
  380. ccxt/pro/vertex.py +8 -3
  381. ccxt/pro/whitebit.py +58 -5
  382. ccxt/pro/woo.py +228 -37
  383. ccxt/pro/woofipro.py +106 -18
  384. ccxt/pro/xt.py +111 -5
  385. ccxt/probit.py +224 -95
  386. ccxt/protobuf/__init__.py +0 -0
  387. ccxt/protobuf/mexc/PrivateAccountV3Api_pb2.py +37 -0
  388. ccxt/protobuf/mexc/PrivateDealsV3Api_pb2.py +37 -0
  389. ccxt/protobuf/mexc/PrivateOrdersV3Api_pb2.py +37 -0
  390. ccxt/protobuf/mexc/PublicAggreBookTickerV3Api_pb2.py +37 -0
  391. ccxt/protobuf/mexc/PublicAggreDealsV3Api_pb2.py +39 -0
  392. ccxt/protobuf/mexc/PublicAggreDepthsV3Api_pb2.py +39 -0
  393. ccxt/protobuf/mexc/PublicBookTickerBatchV3Api_pb2.py +38 -0
  394. ccxt/protobuf/mexc/PublicBookTickerV3Api_pb2.py +37 -0
  395. ccxt/protobuf/mexc/PublicDealsV3Api_pb2.py +39 -0
  396. ccxt/protobuf/mexc/PublicIncreaseDepthsBatchV3Api_pb2.py +38 -0
  397. ccxt/protobuf/mexc/PublicIncreaseDepthsV3Api_pb2.py +39 -0
  398. ccxt/protobuf/mexc/PublicLimitDepthsV3Api_pb2.py +39 -0
  399. ccxt/protobuf/mexc/PublicMiniTickerV3Api_pb2.py +37 -0
  400. ccxt/protobuf/mexc/PublicMiniTickersV3Api_pb2.py +38 -0
  401. ccxt/protobuf/mexc/PublicSpotKlineV3Api_pb2.py +37 -0
  402. ccxt/protobuf/mexc/PushDataV3ApiWrapper_pb2.py +52 -0
  403. ccxt/protobuf/mexc/__init__.py +0 -0
  404. ccxt/ramzinex.py +28 -25
  405. ccxt/sarmayex.py +7 -7
  406. ccxt/sarrafex.py +10 -10
  407. ccxt/static_dependencies/__init__.py +1 -1
  408. ccxt/static_dependencies/lark/py.typed +0 -0
  409. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  410. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  411. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  412. ccxt/tabdeal.py +12 -11
  413. ccxt/test/tests_async.py +261 -57
  414. ccxt/test/tests_helpers.py +1 -3
  415. ccxt/test/tests_init.py +4 -3
  416. ccxt/test/tests_sync.py +261 -57
  417. ccxt/tetherland.py +7 -7
  418. ccxt/timex.py +210 -51
  419. ccxt/tokocrypto.py +167 -47
  420. ccxt/tradeogre.py +266 -31
  421. ccxt/twox.py +7 -7
  422. ccxt/ubitex.py +9 -9
  423. ccxt/upbit.py +568 -165
  424. ccxt/vertex.py +160 -32
  425. ccxt/wallex.py +9 -9
  426. ccxt/wavesexchange.py +165 -30
  427. ccxt/whitebit.py +975 -127
  428. ccxt/woo.py +1917 -1016
  429. ccxt/woofipro.py +432 -141
  430. ccxt/xt.py +649 -193
  431. ccxt/yobit.py +194 -70
  432. ccxt/zaif.py +91 -15
  433. ccxt/zonda.py +151 -36
  434. {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info}/METADATA +225 -73
  435. ccxt_ir-4.5.0.dist-info/RECORD +743 -0
  436. {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info}/WHEEL +1 -1
  437. ccxt/__test__.py +0 -7
  438. ccxt/abstract/ace.py +0 -15
  439. ccxt/abstract/bitbay.py +0 -53
  440. ccxt/abstract/bitcoincom.py +0 -115
  441. ccxt/abstract/bitfinex2.py +0 -139
  442. ccxt/abstract/bitpanda.py +0 -35
  443. ccxt/abstract/bl3p.py +0 -19
  444. ccxt/abstract/coinlist.py +0 -54
  445. ccxt/abstract/currencycom.py +0 -68
  446. ccxt/abstract/hitbtc3.py +0 -115
  447. ccxt/abstract/idex.py +0 -26
  448. ccxt/abstract/kuna.py +0 -182
  449. ccxt/abstract/lykke.py +0 -29
  450. ccxt/abstract/poloniexfutures.py +0 -48
  451. ccxt/abstract/wazirx.py +0 -30
  452. ccxt/ace.py +0 -1012
  453. ccxt/async_support/ace.py +0 -1012
  454. ccxt/async_support/base/ws/aiohttp_client.py +0 -125
  455. ccxt/async_support/base/ws/fast_client.py +0 -96
  456. ccxt/async_support/bitbay.py +0 -17
  457. ccxt/async_support/bitcoincom.py +0 -17
  458. ccxt/async_support/bitfinex2.py +0 -3552
  459. ccxt/async_support/bitpanda.py +0 -16
  460. ccxt/async_support/bl3p.py +0 -485
  461. ccxt/async_support/coinlist.py +0 -2243
  462. ccxt/async_support/currencycom.py +0 -1950
  463. ccxt/async_support/hitbtc3.py +0 -16
  464. ccxt/async_support/idex.py +0 -1766
  465. ccxt/async_support/kuna.py +0 -1841
  466. ccxt/async_support/lykke.py +0 -1270
  467. ccxt/async_support/poloniexfutures.py +0 -1717
  468. ccxt/async_support/wazirx.py +0 -1224
  469. ccxt/bitbay.py +0 -17
  470. ccxt/bitcoincom.py +0 -17
  471. ccxt/bitfinex2.py +0 -3552
  472. ccxt/bitpanda.py +0 -16
  473. ccxt/bl3p.py +0 -485
  474. ccxt/coinlist.py +0 -2243
  475. ccxt/currencycom.py +0 -1950
  476. ccxt/hitbtc3.py +0 -16
  477. ccxt/idex.py +0 -1766
  478. ccxt/kuna.py +0 -1841
  479. ccxt/lykke.py +0 -1270
  480. ccxt/poloniexfutures.py +0 -1717
  481. ccxt/pro/bitcoincom.py +0 -34
  482. ccxt/pro/bitfinex2.py +0 -1083
  483. ccxt/pro/bitpanda.py +0 -15
  484. ccxt/pro/currencycom.py +0 -536
  485. ccxt/pro/idex.py +0 -672
  486. ccxt/pro/poloniexfutures.py +0 -990
  487. ccxt/pro/wazirx.py +0 -749
  488. ccxt/test/base/__init__.py +0 -29
  489. ccxt/test/base/test_account.py +0 -26
  490. ccxt/test/base/test_balance.py +0 -56
  491. ccxt/test/base/test_borrow_interest.py +0 -35
  492. ccxt/test/base/test_borrow_rate.py +0 -32
  493. ccxt/test/base/test_calculate_fee.py +0 -51
  494. ccxt/test/base/test_crypto.py +0 -127
  495. ccxt/test/base/test_currency.py +0 -76
  496. ccxt/test/base/test_datetime.py +0 -109
  497. ccxt/test/base/test_decimal_to_precision.py +0 -392
  498. ccxt/test/base/test_deep_extend.py +0 -68
  499. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  500. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  501. ccxt/test/base/test_funding_rate_history.py +0 -29
  502. ccxt/test/base/test_last_price.py +0 -31
  503. ccxt/test/base/test_ledger_entry.py +0 -45
  504. ccxt/test/base/test_ledger_item.py +0 -48
  505. ccxt/test/base/test_leverage_tier.py +0 -33
  506. ccxt/test/base/test_liquidation.py +0 -50
  507. ccxt/test/base/test_margin_mode.py +0 -24
  508. ccxt/test/base/test_margin_modification.py +0 -35
  509. ccxt/test/base/test_market.py +0 -193
  510. ccxt/test/base/test_number.py +0 -411
  511. ccxt/test/base/test_ohlcv.py +0 -33
  512. ccxt/test/base/test_open_interest.py +0 -32
  513. ccxt/test/base/test_order.py +0 -64
  514. ccxt/test/base/test_order_book.py +0 -69
  515. ccxt/test/base/test_position.py +0 -60
  516. ccxt/test/base/test_shared_methods.py +0 -353
  517. ccxt/test/base/test_status.py +0 -24
  518. ccxt/test/base/test_throttle.py +0 -126
  519. ccxt/test/base/test_ticker.py +0 -92
  520. ccxt/test/base/test_trade.py +0 -47
  521. ccxt/test/base/test_trading_fee.py +0 -26
  522. ccxt/test/base/test_transaction.py +0 -39
  523. ccxt/test/test_async.py +0 -1649
  524. ccxt/test/test_sync.py +0 -1648
  525. ccxt/wazirx.py +0 -1224
  526. ccxt_ir-4.3.46.0.3.dist-info/RECORD +0 -773
  527. /ccxt/abstract/{huobijp.py → bittrade.py} +0 -0
  528. {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info/licenses}/LICENSE.txt +0 -0
  529. {ccxt_ir-4.3.46.0.3.dist-info → ccxt_ir-4.5.0.dist-info}/top_level.txt +0 -0
ccxt/pro/bitfinex.py CHANGED
@@ -4,19 +4,20 @@
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 Any, 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
 
17
18
  class bitfinex(ccxt.async_support.bitfinex):
18
19
 
19
- def describe(self):
20
+ def describe(self) -> Any:
20
21
  return self.deep_extend(super(bitfinex, self).describe(), {
21
22
  'has': {
22
23
  'ws': True,
@@ -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
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
  """
@@ -250,13 +510,11 @@ class bitfinex(ccxt.async_support.bitfinex):
250
510
  prec = self.safe_string(options, 'prec', 'P0')
251
511
  freq = self.safe_string(options, 'freq', 'F0')
252
512
  request: dict = {
253
- # "event": "subscribe", # added in subscribe()
254
- # "channel": channel, # added in subscribe()
255
- # "symbol": marketId, # added in subscribe()
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.storeArray([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.storeArray([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.storeArray([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.storeArray([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')
810
+ event = 'auth'
396
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
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: dict = {
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
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
  }