Qubx 0.6.32__tar.gz → 0.6.35__tar.gz

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 (158) hide show
  1. {qubx-0.6.32 → qubx-0.6.35}/PKG-INFO +2 -1
  2. {qubx-0.6.32 → qubx-0.6.35}/pyproject.toml +2 -1
  3. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/broker.py +4 -1
  4. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/exchanges/__init__.py +2 -0
  5. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +91 -0
  6. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/tardis/data.py +5 -2
  7. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/runner/runner.py +7 -7
  8. {qubx-0.6.32 → qubx-0.6.35}/LICENSE +0 -0
  9. {qubx-0.6.32 → qubx-0.6.35}/README.md +0 -0
  10. {qubx-0.6.32 → qubx-0.6.35}/build.py +0 -0
  11. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/__init__.py +0 -0
  12. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/_nb_magic.py +0 -0
  13. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/__init__.py +0 -0
  14. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/account.py +0 -0
  15. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/broker.py +0 -0
  16. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/data.py +0 -0
  17. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/management.py +0 -0
  18. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/ome.py +0 -0
  19. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/optimization.py +0 -0
  20. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/runner.py +0 -0
  21. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/simulated_data.py +0 -0
  22. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/simulated_exchange.py +0 -0
  23. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/simulator.py +0 -0
  24. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/backtester/utils.py +0 -0
  25. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/cli/__init__.py +0 -0
  26. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/cli/commands.py +0 -0
  27. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/cli/deploy.py +0 -0
  28. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/cli/misc.py +0 -0
  29. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/cli/release.py +0 -0
  30. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/__init__.py +0 -0
  31. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/account.py +0 -0
  32. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/data.py +0 -0
  33. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  34. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
  35. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
  36. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
  37. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
  38. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/factory.py +0 -0
  39. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/reader.py +0 -0
  40. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/ccxt/utils.py +0 -0
  41. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/connectors/tardis/utils.py +0 -0
  42. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/__init__.py +0 -0
  43. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/account.py +0 -0
  44. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/basics.py +0 -0
  45. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/context.py +0 -0
  46. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/deque.py +0 -0
  47. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/errors.py +0 -0
  48. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/exceptions.py +0 -0
  49. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/helpers.py +0 -0
  50. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/initializer.py +0 -0
  51. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/interfaces.py +0 -0
  52. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/loggers.py +0 -0
  53. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/lookups.py +0 -0
  54. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/metrics.py +0 -0
  55. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/mixins/__init__.py +0 -0
  56. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/mixins/market.py +0 -0
  57. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/mixins/processing.py +0 -0
  58. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/mixins/subscription.py +0 -0
  59. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/mixins/trading.py +0 -0
  60. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/mixins/universe.py +0 -0
  61. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/series.pxd +0 -0
  62. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/series.pyi +0 -0
  63. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/series.pyx +0 -0
  64. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/utils.pyi +0 -0
  65. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/core/utils.pyx +0 -0
  66. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/data/__init__.py +0 -0
  67. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/data/composite.py +0 -0
  68. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/data/helpers.py +0 -0
  69. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/data/hft.py +0 -0
  70. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/data/readers.py +0 -0
  71. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/data/registry.py +0 -0
  72. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/data/tardis.py +0 -0
  73. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/emitters/__init__.py +0 -0
  74. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/emitters/base.py +0 -0
  75. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/emitters/composite.py +0 -0
  76. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/emitters/csv.py +0 -0
  77. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/emitters/prometheus.py +0 -0
  78. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/emitters/questdb.py +0 -0
  79. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/__init__.py +0 -0
  80. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/composite.py +0 -0
  81. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/formatters/__init__.py +0 -0
  82. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/formatters/base.py +0 -0
  83. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/formatters/incremental.py +0 -0
  84. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/formatters/slack.py +0 -0
  85. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/redis_streams.py +0 -0
  86. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/exporters/slack.py +0 -0
  87. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/features/__init__.py +0 -0
  88. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/features/core.py +0 -0
  89. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/features/orderbook.py +0 -0
  90. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/features/price.py +0 -0
  91. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/features/trades.py +0 -0
  92. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/features/utils.py +0 -0
  93. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/gathering/simplest.py +0 -0
  94. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/health/__init__.py +0 -0
  95. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/health/base.py +0 -0
  96. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/math/__init__.py +0 -0
  97. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/math/stats.py +0 -0
  98. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/notifications/__init__.py +0 -0
  99. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/notifications/composite.py +0 -0
  100. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/notifications/slack.py +0 -0
  101. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/pandaz/__init__.py +0 -0
  102. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/pandaz/ta.py +0 -0
  103. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/pandaz/utils.py +0 -0
  104. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/_build.py +0 -0
  105. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/instruments/symbols-binance.cm.json +0 -0
  106. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/instruments/symbols-binance.json +0 -0
  107. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/instruments/symbols-binance.um.json +0 -0
  108. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/instruments/symbols-bitfinex.f.json +0 -0
  109. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/instruments/symbols-bitfinex.json +0 -0
  110. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/instruments/symbols-kraken.f.json +0 -0
  111. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/resources/instruments/symbols-kraken.json +0 -0
  112. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restarts/__init__.py +0 -0
  113. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restarts/state_resolvers.py +0 -0
  114. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restarts/time_finders.py +0 -0
  115. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/__init__.py +0 -0
  116. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/balance.py +0 -0
  117. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/factory.py +0 -0
  118. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/interfaces.py +0 -0
  119. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/position.py +0 -0
  120. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/signal.py +0 -0
  121. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/state.py +0 -0
  122. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/restorers/utils.py +0 -0
  123. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/ta/__init__.py +0 -0
  124. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/ta/indicators.pxd +0 -0
  125. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/ta/indicators.pyi +0 -0
  126. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/ta/indicators.pyx +0 -0
  127. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/trackers/__init__.py +0 -0
  128. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/trackers/advanced.py +0 -0
  129. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/trackers/composite.py +0 -0
  130. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/trackers/rebalancers.py +0 -0
  131. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/trackers/riskctrl.py +0 -0
  132. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/trackers/sizers.py +0 -0
  133. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/__init__.py +0 -0
  134. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/_pyxreloader.py +0 -0
  135. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/charting/lookinglass.py +0 -0
  136. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  137. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/collections.py +0 -0
  138. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/marketdata/binance.py +0 -0
  139. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/marketdata/ccxt.py +0 -0
  140. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/marketdata/dukas.py +0 -0
  141. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/misc.py +0 -0
  142. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/ntp.py +0 -0
  143. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/numbers_utils.py +0 -0
  144. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/orderbook.py +0 -0
  145. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/plotting/__init__.py +0 -0
  146. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/plotting/dashboard.py +0 -0
  147. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/plotting/data.py +0 -0
  148. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/plotting/interfaces.py +0 -0
  149. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  150. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  151. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/questdb.py +0 -0
  152. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/runner/__init__.py +0 -0
  153. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
  154. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/runner/accounts.py +0 -0
  155. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/runner/configs.py +0 -0
  156. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/runner/factory.py +0 -0
  157. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/time.py +0 -0
  158. {qubx-0.6.32 → qubx-0.6.35}/src/qubx/utils/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: Qubx
3
- Version: 0.6.32
3
+ Version: 0.6.35
4
4
  Summary: Qubx - Quantitative Trading Framework
5
5
  Author: Dmitry Marienko
6
6
  Author-email: dmitry.marienko@xlydian.com
@@ -11,6 +11,7 @@ Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3.13
13
13
  Requires-Dist: aiohttp (>=3.10.11,<3.11.0)
14
+ Requires-Dist: bitfinex-api-py (>=3.0.4,<4.0.0)
14
15
  Requires-Dist: ccxt (>=4.2.68,<5.0.0)
15
16
  Requires-Dist: croniter (>=2.0.5,<3.0.0)
16
17
  Requires-Dist: cython (==3.0.8)
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "Qubx"
7
- version = "0.6.32"
7
+ version = "0.6.35"
8
8
  description = "Qubx - Quantitative Trading Framework"
9
9
  authors = [ "Dmitry Marienko <dmitry.marienko@xlydian.com>", "Yuriy Arabskyy <yuriy.arabskyy@xlydian.com>",]
10
10
  readme = "README.md"
@@ -72,6 +72,7 @@ ipywidgets = "^8.1.5"
72
72
  questdb = "^2.0.3"
73
73
  orjson = "^3.10.15"
74
74
  aiohttp = "~3.10.11"
75
+ bitfinex-api-py = "^3.0.4"
75
76
 
76
77
  [tool.ruff.lint]
77
78
  extend-select = [ "I",]
@@ -168,7 +168,7 @@ class CcxtBroker(IBroker):
168
168
  raise error
169
169
 
170
170
  # If there was no error but also no order, something went wrong
171
- if not order:
171
+ if not order and not self.enable_create_order_ws:
172
172
  raise ExchangeError("Order creation failed with no specific error")
173
173
 
174
174
  return order
@@ -224,6 +224,9 @@ class CcxtBroker(IBroker):
224
224
  logger.error(msg)
225
225
  return None, ExchangeError(msg)
226
226
 
227
+ if r["id"] is None:
228
+ return None, None
229
+
227
230
  order = ccxt_convert_order_info(instrument, r)
228
231
  logger.info(f"New order {order}")
229
232
  return order, None
@@ -6,6 +6,7 @@ from functools import partial
6
6
 
7
7
  import ccxt.pro as cxp
8
8
 
9
+ from ..broker import CcxtBroker
9
10
  from .binance.broker import BinanceCcxtBroker
10
11
  from .binance.exchange import BINANCE_UM_MM, BinancePortfolioMargin, BinanceQV, BinanceQVUSDM
11
12
  from .bitfinex.bitfinex import BitfinexF
@@ -27,6 +28,7 @@ CUSTOM_BROKERS = {
27
28
  "binance.um": partial(BinanceCcxtBroker, enable_create_order_ws=True, enable_cancel_order_ws=False),
28
29
  "binance.cm": partial(BinanceCcxtBroker, enable_create_order_ws=True, enable_cancel_order_ws=False),
29
30
  "binance.pm": partial(BinanceCcxtBroker, enable_create_order_ws=False, enable_cancel_order_ws=False),
31
+ "bitfinex.f": partial(CcxtBroker, enable_create_order_ws=True, enable_cancel_order_ws=True),
30
32
  }
31
33
 
32
34
  CUSTOM_ACCOUNTS = {
@@ -1,6 +1,11 @@
1
+ import asyncio
2
+ from dataclasses import asdict
1
3
  from typing import Dict, List
2
4
 
3
5
  import ccxt.pro as cxp
6
+ from bfxapi import REST_HOST
7
+ from bfxapi import Client as BfxClient
8
+ from bfxapi.types import Order as BfxOrder
4
9
  from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheByTimestamp
5
10
  from ccxt.async_support.base.ws.client import Client
6
11
  from ccxt.base.errors import ArgumentsRequired, BadRequest, NotSupported
@@ -19,12 +24,26 @@ from ccxt.base.types import (
19
24
  Tickers,
20
25
  )
21
26
 
27
+ from qubx import logger
28
+
22
29
 
23
30
  class BitfinexF(cxp.bitfinex):
24
31
  """
25
32
  Extended binance exchange to provide quote asset volumes support
26
33
  """
27
34
 
35
+ def __init__(self, *args, **kwargs):
36
+ super().__init__(*args, **kwargs)
37
+
38
+ # we are adding here the official bitfinex client to extend missing functionality
39
+ self.bfx = BfxClient(rest_host=REST_HOST, api_key=self.apiKey, api_secret=self.secret)
40
+
41
+ @self.bfx.wss.on("authenticated")
42
+ def on_authenticated(data: dict[str, Any]):
43
+ logger.info(f"Successful login for user {data['userId']}.")
44
+
45
+ asyncio.run_coroutine_threadsafe(self.bfx.wss.start(), self.asyncio_loop)
46
+
28
47
  def describe(self):
29
48
  """
30
49
  Overriding watchTrades to use aggTrade instead of trade.
@@ -34,6 +53,8 @@ class BitfinexF(cxp.bitfinex):
34
53
  {
35
54
  "has": {
36
55
  "watchBidsAsks": True,
56
+ "createOrderWs": True,
57
+ "cancelOrderWs": True,
37
58
  }
38
59
  },
39
60
  )
@@ -60,6 +81,37 @@ class BitfinexF(cxp.bitfinex):
60
81
  response = await super().create_order(symbol, type, side, amount, price, params)
61
82
  return response
62
83
 
84
+ async def create_order_ws(
85
+ self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}
86
+ ) -> Order:
87
+ params.pop("type", None)
88
+ if "timeInForce" in params and params["timeInForce"] == "GTX":
89
+ # GTX is not supported by bitfinex, so we need to convert it to PO
90
+ params["timeInForce"] = "PO"
91
+ params["postOnly"] = True
92
+
93
+ await self.load_markets()
94
+ market = self.market(symbol)
95
+ request = self.create_order_request(symbol, type, side, amount, price, params)
96
+
97
+ # if "newClientOrderId" in request:
98
+ # request["cid"] = request["newClientOrderId"]
99
+ # del request["newClientOrderId"]
100
+
101
+ await self.bfx.wss.inputs.submit_order(
102
+ type=request["type"],
103
+ symbol=request["symbol"],
104
+ amount=float(request["amount"]),
105
+ price=float(request["price"]),
106
+ flags=request["flags"],
107
+ # cid=int(request["cid"]),
108
+ )
109
+ return self.safe_order({"info": {}}, market) # type: ignore
110
+
111
+ async def cancel_order_ws(self, id: str, symbol: Str = None, params={}) -> Order | None:
112
+ await self.bfx.wss.inputs.cancel_order(id=int(id))
113
+ return None
114
+
63
115
  async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
64
116
  response = await super().watch_orders(symbol, since, limit, params)
65
117
  return response
@@ -165,3 +217,42 @@ class BitfinexF(cxp.bitfinex):
165
217
  "takeProfitPrice": None,
166
218
  }
167
219
  )
220
+
221
+ def _bfx_order_to_ccxt_order(self, bfx_order: BfxOrder, market: Market = None) -> Order:
222
+ flags = self.parse_order_flags(bfx_order.flags)
223
+ postOnly = False
224
+ if flags is not None:
225
+ for i in range(0, len(flags)):
226
+ if flags[i] == "postOnly":
227
+ postOnly = True
228
+
229
+ side = "sell" if Precise.string_lt(bfx_order.amount, "0") else "buy"
230
+ timeInForce = self.parse_time_in_force(bfx_order.order_type)
231
+ type = self.safe_string(self.safe_value(self.options, "exchangeTypes"), bfx_order.order_type)
232
+
233
+ return self.safe_order(
234
+ {
235
+ "info": asdict(bfx_order),
236
+ "id": str(bfx_order.id),
237
+ "clientOrderId": str(bfx_order.cid),
238
+ "timestamp": bfx_order.mts_create,
239
+ "datetime": self.iso8601(bfx_order.mts_create),
240
+ "lastTradeTimestamp": None,
241
+ "symbol": self.safe_symbol(bfx_order.symbol, market),
242
+ "type": type,
243
+ "timeInForce": timeInForce,
244
+ "postOnly": postOnly,
245
+ "side": side,
246
+ "price": bfx_order.price,
247
+ "triggerPrice": None,
248
+ "amount": bfx_order.amount,
249
+ "cost": None,
250
+ "average": bfx_order.price_avg,
251
+ "filled": None,
252
+ "remaining": None,
253
+ "status": None,
254
+ "fee": None,
255
+ "trades": None,
256
+ },
257
+ market,
258
+ ) # type: ignore
@@ -20,7 +20,7 @@ from qubx.core.interfaces import IDataProvider, IHealthMonitor
20
20
  from qubx.core.series import Bar, Quote, Trade
21
21
  from qubx.data.tardis import TARDIS_EXCHANGE_MAPPERS
22
22
  from qubx.health import DummyHealthMonitor
23
- from qubx.utils.misc import AsyncThreadLoop
23
+ from qubx.utils.misc import AsyncThreadLoop, synchronized
24
24
 
25
25
  from .utils import (
26
26
  tardis_convert_orderbook,
@@ -354,6 +354,7 @@ class TardisDataProvider(IDataProvider):
354
354
  self._symbol_to_instrument[tardis_symbol] = instrument
355
355
  return tardis_symbol
356
356
 
357
+ @synchronized
357
358
  async def _start_websocket_connection(self):
358
359
  """Start the WebSocket connection to Tardis Machine."""
359
360
  if not self._subscriptions:
@@ -420,6 +421,7 @@ class TardisDataProvider(IDataProvider):
420
421
  except Exception as e:
421
422
  logger.error(f"{self.__prefix()} WebSocket error: {e}")
422
423
  finally:
424
+ logger.info(f"{self.__prefix()} WebSocket connection closed")
423
425
  self._ws = None
424
426
 
425
427
  async def _close_websocket_connection(self):
@@ -452,6 +454,7 @@ class TardisDataProvider(IDataProvider):
452
454
 
453
455
  # Record data arrival for health monitoring
454
456
  tardis_type = data["type"]
457
+ tardis_name = data["name"]
455
458
  qubx_type = self._map_tardis_type_to_data_type(tardis_type)
456
459
  if qubx_type:
457
460
  self._health_monitor.record_data_arrival(qubx_type, dt_64(msg_time, "ns"))
@@ -468,7 +471,7 @@ class TardisDataProvider(IDataProvider):
468
471
  # This is a simplified implementation
469
472
  pass
470
473
 
471
- elif tardis_type == "quote":
474
+ elif tardis_type == "quote" or tardis_name == "quote":
472
475
  if DataType.QUOTE in self._subscriptions and instrument in self._subscriptions[DataType.QUOTE]:
473
476
  quote = tardis_convert_quote(data, instrument)
474
477
  if quote:
@@ -463,10 +463,10 @@ def _create_account_processor(
463
463
  restored_state: RestoredState | None = None,
464
464
  read_only: bool = False,
465
465
  ) -> IAccountProcessor:
466
- if exchange_config.account is not None:
467
- connector = exchange_config.account.connector
468
- elif paper:
466
+ if paper:
469
467
  connector = "paper"
468
+ elif exchange_config.account is not None:
469
+ connector = exchange_config.account.connector
470
470
  else:
471
471
  connector = exchange_config.connector
472
472
 
@@ -514,12 +514,12 @@ def _create_broker(
514
514
  account_manager: AccountConfigurationManager,
515
515
  paper: bool,
516
516
  ) -> IBroker:
517
- if exchange_config.broker is not None:
518
- connector = exchange_config.broker.connector
519
- params = exchange_config.broker.params
520
- elif paper:
517
+ if paper:
521
518
  connector = "paper"
522
519
  params = {}
520
+ elif exchange_config.broker is not None:
521
+ connector = exchange_config.broker.connector
522
+ params = exchange_config.broker.params
523
523
  else:
524
524
  connector = exchange_config.connector
525
525
  params = exchange_config.params
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes