Qubx 0.6.11__tar.gz → 0.6.13__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.

Potentially problematic release.


This version of Qubx might be problematic. Click here for more details.

Files changed (141) hide show
  1. {qubx-0.6.11 → qubx-0.6.13}/PKG-INFO +1 -1
  2. {qubx-0.6.11 → qubx-0.6.13}/pyproject.toml +1 -1
  3. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/account.py +3 -2
  4. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/basics.py +17 -12
  5. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/loggers.py +22 -12
  6. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restarts/state_resolvers.py +1 -1
  7. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/signal.py +6 -1
  8. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/runner/_jupyter_runner.pyt +3 -3
  9. {qubx-0.6.11 → qubx-0.6.13}/README.md +0 -0
  10. {qubx-0.6.11 → qubx-0.6.13}/build.py +0 -0
  11. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/__init__.py +0 -0
  12. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/_nb_magic.py +0 -0
  13. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/__init__.py +0 -0
  14. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/account.py +0 -0
  15. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/broker.py +0 -0
  16. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/data.py +0 -0
  17. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/management.py +0 -0
  18. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/ome.py +0 -0
  19. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/optimization.py +0 -0
  20. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/runner.py +0 -0
  21. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/simulated_data.py +0 -0
  22. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/simulator.py +0 -0
  23. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/backtester/utils.py +0 -0
  24. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/cli/__init__.py +0 -0
  25. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/cli/commands.py +0 -0
  26. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/cli/deploy.py +0 -0
  27. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/cli/misc.py +0 -0
  28. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/cli/release.py +0 -0
  29. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/__init__.py +0 -0
  30. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/account.py +0 -0
  31. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/broker.py +0 -0
  32. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/customizations.py +0 -0
  33. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/data.py +0 -0
  34. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/exceptions.py +0 -0
  35. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/factory.py +0 -0
  36. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/reader.py +0 -0
  37. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/connectors/ccxt/utils.py +0 -0
  38. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/__init__.py +0 -0
  39. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/context.py +0 -0
  40. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/exceptions.py +0 -0
  41. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/helpers.py +0 -0
  42. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/initializer.py +0 -0
  43. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/interfaces.py +0 -0
  44. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/lookups.py +0 -0
  45. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/metrics.py +0 -0
  46. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/mixins/__init__.py +0 -0
  47. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/mixins/market.py +0 -0
  48. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/mixins/processing.py +0 -0
  49. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/mixins/subscription.py +0 -0
  50. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/mixins/trading.py +0 -0
  51. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/mixins/universe.py +0 -0
  52. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/series.pxd +0 -0
  53. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/series.pyi +0 -0
  54. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/series.pyx +0 -0
  55. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/utils.pyi +0 -0
  56. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/core/utils.pyx +0 -0
  57. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/data/__init__.py +0 -0
  58. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/data/composite.py +0 -0
  59. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/data/helpers.py +0 -0
  60. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/data/hft.py +0 -0
  61. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/data/readers.py +0 -0
  62. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/data/registry.py +0 -0
  63. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/data/tardis.py +0 -0
  64. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/emitters/__init__.py +0 -0
  65. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/emitters/base.py +0 -0
  66. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/emitters/composite.py +0 -0
  67. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/emitters/prometheus.py +0 -0
  68. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/emitters/questdb.py +0 -0
  69. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/__init__.py +0 -0
  70. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/composite.py +0 -0
  71. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/formatters/__init__.py +0 -0
  72. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/formatters/base.py +0 -0
  73. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/formatters/incremental.py +0 -0
  74. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/formatters/slack.py +0 -0
  75. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/redis_streams.py +0 -0
  76. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/exporters/slack.py +0 -0
  77. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/features/__init__.py +0 -0
  78. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/features/core.py +0 -0
  79. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/features/orderbook.py +0 -0
  80. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/features/price.py +0 -0
  81. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/features/trades.py +0 -0
  82. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/features/utils.py +0 -0
  83. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/gathering/simplest.py +0 -0
  84. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/math/__init__.py +0 -0
  85. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/math/stats.py +0 -0
  86. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/notifications/__init__.py +0 -0
  87. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/notifications/composite.py +0 -0
  88. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/notifications/slack.py +0 -0
  89. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/pandaz/__init__.py +0 -0
  90. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/pandaz/ta.py +0 -0
  91. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/pandaz/utils.py +0 -0
  92. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/_build.py +0 -0
  93. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/instruments/symbols-binance.cm.json +0 -0
  94. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/instruments/symbols-binance.json +0 -0
  95. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/instruments/symbols-binance.um.json +0 -0
  96. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/instruments/symbols-bitfinex.f.json +0 -0
  97. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/instruments/symbols-bitfinex.json +0 -0
  98. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/instruments/symbols-kraken.f.json +0 -0
  99. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/resources/instruments/symbols-kraken.json +0 -0
  100. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restarts/__init__.py +0 -0
  101. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restarts/time_finders.py +0 -0
  102. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/__init__.py +0 -0
  103. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/balance.py +0 -0
  104. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/factory.py +0 -0
  105. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/interfaces.py +0 -0
  106. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/position.py +0 -0
  107. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/state.py +0 -0
  108. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/restorers/utils.py +0 -0
  109. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/ta/__init__.py +0 -0
  110. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/ta/indicators.pxd +0 -0
  111. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/ta/indicators.pyi +0 -0
  112. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/ta/indicators.pyx +0 -0
  113. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/trackers/__init__.py +0 -0
  114. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/trackers/advanced.py +0 -0
  115. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/trackers/composite.py +0 -0
  116. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/trackers/rebalancers.py +0 -0
  117. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/trackers/riskctrl.py +0 -0
  118. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/trackers/sizers.py +0 -0
  119. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/__init__.py +0 -0
  120. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/_pyxreloader.py +0 -0
  121. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/charting/lookinglass.py +0 -0
  122. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  123. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/marketdata/binance.py +0 -0
  124. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/marketdata/ccxt.py +0 -0
  125. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/marketdata/dukas.py +0 -0
  126. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/misc.py +0 -0
  127. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/ntp.py +0 -0
  128. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/numbers_utils.py +0 -0
  129. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/orderbook.py +0 -0
  130. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/plotting/__init__.py +0 -0
  131. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/plotting/dashboard.py +0 -0
  132. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/plotting/data.py +0 -0
  133. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/plotting/interfaces.py +0 -0
  134. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
  135. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
  136. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/runner/__init__.py +0 -0
  137. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/runner/accounts.py +0 -0
  138. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/runner/configs.py +0 -0
  139. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/runner/runner.py +0 -0
  140. {qubx-0.6.11 → qubx-0.6.13}/src/qubx/utils/time.py +0 -0
  141. {qubx-0.6.11 → qubx-0.6.13}/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.11
3
+ Version: 0.6.13
4
4
  Summary: Qubx - Quantitative Trading Framework
5
5
  Author: Dmitry Marienko
6
6
  Author-email: dmitry.marienko@xlydian.com
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "Qubx"
7
- version = "0.6.11"
7
+ version = "0.6.13"
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"
@@ -175,8 +175,9 @@ class BasicAccountProcessor(IAccountProcessor):
175
175
  self._lock_limit_order_value(order)
176
176
 
177
177
  if _closed or _cancel:
178
- if order.id in self._processed_trades:
179
- self._processed_trades.pop(order.id)
178
+ # TODO: (LIVE) WE NEED TO THINK HOW TO CLEANUP THIS COLLECTION !!!! -> @DM
179
+ # if order.id in self._processed_trades:
180
+ # self._processed_trades.pop(order.id)
180
181
 
181
182
  if order.id in self._active_orders:
182
183
  self._active_orders.pop(order.id)
@@ -8,7 +8,6 @@ from typing import Any, Literal, Optional, TypeAlias, Union
8
8
  import numpy as np
9
9
  import pandas as pd
10
10
 
11
- from qubx import logger
12
11
  from qubx.core.exceptions import QueueTimeout
13
12
  from qubx.core.series import Bar, OrderBook, Quote, Trade, time_as_nsec
14
13
  from qubx.core.utils import prec_ceil, prec_floor, time_delta_to_str
@@ -476,6 +475,7 @@ class Position:
476
475
  self.quantity = quantity
477
476
  self.position_avg_price = pos_average_price
478
477
  self.r_pnl = r_pnl
478
+ self.__pos_incr_qty = abs(quantity)
479
479
 
480
480
  def reset(self) -> None:
481
481
  """
@@ -540,6 +540,7 @@ class Position:
540
540
  deal_pnl = 0
541
541
  quantity = self.quantity
542
542
  comms = 0
543
+ # logger.info(f"{self.instrument.symbol} exec_price={exec_price} fee_amount={fee_amount} position={position}")
543
544
 
544
545
  if quantity != position:
545
546
  pos_change = position - quantity
@@ -558,6 +559,10 @@ class Position:
558
559
  quantity += qty_closing
559
560
  self.__pos_incr_qty -= _abs_qty_close
560
561
 
562
+ # logger.info(
563
+ # f"{self.instrument.symbol} qty_closing={qty_closing} deal_pnl={deal_pnl} quantity={quantity} pos_incr_qty={self.__pos_incr_qty} position_avg_price={self.position_avg_price}"
564
+ # )
565
+
561
566
  # - reset average price to 0 if smaller than minimal price change to avoid cumulative error
562
567
  if abs(quantity) < self.instrument.lot_size:
563
568
  quantity = 0.0
@@ -567,16 +572,14 @@ class Position:
567
572
  # - if it has something to add to position let's update price and cost
568
573
  if not np.isclose(qty_opening, 0.0):
569
574
  _abs_qty_open = abs(qty_opening)
570
- try:
571
- pos_avg_price_raw = (_abs_qty_open * exec_price + self.__pos_incr_qty * self.position_avg_price) / (
572
- self.__pos_incr_qty + _abs_qty_open
573
- )
574
- except ZeroDivisionError:
575
- logger.warning(
576
- "Zero division error in position update: "
577
- f"qty_opening={qty_opening}, exec_price={exec_price}, pos_incr_qty={self.__pos_incr_qty}, position_avg_price={self.position_avg_price}"
578
- )
579
- pos_avg_price_raw = self.position_avg_price
575
+
576
+ # logger.info(
577
+ # f"{self.instrument.symbol} qty_opening={qty_opening} exec_price={exec_price} pos_incr_qty={self.__pos_incr_qty} position_avg_price={self.position_avg_price}"
578
+ # )
579
+
580
+ pos_avg_price_raw = (_abs_qty_open * exec_price + self.__pos_incr_qty * self.position_avg_price) / (
581
+ self.__pos_incr_qty + _abs_qty_open
582
+ )
580
583
 
581
584
  # - round position average price to be in line with how it's calculated by broker
582
585
  self.position_avg_price = self.instrument.round_price_down(pos_avg_price_raw)
@@ -676,7 +679,9 @@ class Position:
676
679
  f"qty={self.quantity:.{self.instrument.size_precision}f}",
677
680
  f"entryPrice={self.position_avg_price:.{self.instrument.price_precision}f}",
678
681
  f"price={self.last_update_price:.{self.instrument.price_precision}f}",
679
- f"pnl={self.unrealized_pnl():.2f}",
682
+ f"PNL: (unrealized={self.unrealized_pnl():.2f}",
683
+ f"realized={self.r_pnl:.2f}",
684
+ f"pnl={self.pnl:.2f})",
680
685
  f"value={self.market_value_funds:.2f}",
681
686
  ]
682
687
  )
@@ -216,8 +216,10 @@ class _BaseIntervalDumper:
216
216
  def store(self, timestamp: np.datetime64):
217
217
  _t_ns = time_as_nsec(timestamp)
218
218
  if self._freq:
219
- _interval_start_time = int(_t_ns - _t_ns % self._freq)
220
- if _t_ns - self._last_log_time_ns >= self._freq:
219
+ # Convert freq to nanoseconds for calculation
220
+ _freq_ns = self._freq.astype("int64")
221
+ _interval_start_time = int(_t_ns - (_t_ns % _freq_ns))
222
+ if _t_ns - self._last_log_time_ns >= _freq_ns:
221
223
  self.dump(np.datetime64(_interval_start_time, "ns"), timestamp)
222
224
  self._last_log_time_ns = _interval_start_time
223
225
  else:
@@ -412,22 +414,29 @@ class SignalsLogger(_BaseIntervalDumper):
412
414
 
413
415
  class BalanceLogger(_BaseIntervalDumper):
414
416
  """
415
- Balance logger - send balance on strategy start
417
+ Balance logger - save balance information at regular intervals similar to positions
416
418
  """
417
419
 
418
420
  _writer: LogsWriter
421
+ _balance: dict[str, AssetBalance]
419
422
 
420
- def __init__(self, writer: LogsWriter) -> None:
421
- super().__init__(None) # no intervals
423
+ def __init__(self, writer: LogsWriter, interval: str) -> None:
424
+ super().__init__(interval)
422
425
  self._writer = writer
426
+ self._balance = {}
423
427
 
424
- def record_balance(self, timestamp: np.datetime64, balance: Dict[str, AssetBalance]):
428
+ def record_balance(self, timestamp: np.datetime64, balance: dict[str, AssetBalance]):
425
429
  if balance:
430
+ self._balance = balance
431
+ self.dump(timestamp, timestamp)
432
+
433
+ def dump(self, interval_start_time: np.datetime64, actual_timestamp: np.datetime64):
434
+ if self._balance:
426
435
  data = []
427
- for s, d in balance.items():
436
+ for s, d in self._balance.items():
428
437
  data.append(
429
438
  {
430
- "timestamp": timestamp,
439
+ "timestamp": str(interval_start_time),
431
440
  "currency": s,
432
441
  "total": d.total,
433
442
  "locked": d.locked,
@@ -435,9 +444,6 @@ class BalanceLogger(_BaseIntervalDumper):
435
444
  )
436
445
  self._writer.write_data("balance", data)
437
446
 
438
- def store(self, timestamp: np.datetime64):
439
- pass
440
-
441
447
  def close(self):
442
448
  self._writer.flush_data()
443
449
 
@@ -484,7 +490,7 @@ class StrategyLogging:
484
490
  self.signals_logger = SignalsLogger(logs_writer, num_signals_records_to_write)
485
491
 
486
492
  # - balance logger
487
- self.balance_logger = BalanceLogger(logs_writer)
493
+ self.balance_logger = BalanceLogger(logs_writer, positions_log_freq)
488
494
  else:
489
495
  logger.warning("Log writer is not defined - strategy activity will not be saved !")
490
496
 
@@ -534,6 +540,10 @@ class StrategyLogging:
534
540
  if self.portfolio_logger:
535
541
  self.portfolio_logger.store(timestamp)
536
542
 
543
+ # - notify balance logger
544
+ if self.balance_logger:
545
+ self.balance_logger.store(timestamp)
546
+
537
547
  # - log heartbeat
538
548
  self._log_heartbeat(timestamp)
539
549
 
@@ -43,7 +43,7 @@ class StateResolver:
43
43
  ctx.trade(instrument, -live_qty)
44
44
 
45
45
  # If live position is larger than sim position (same direction), reduce it
46
- elif abs(live_qty) > abs(sim_qty) and abs(sim_qty) > instrument.lot_size:
46
+ elif abs(live_qty) > abs(sim_qty) and abs(live_qty) > instrument.lot_size:
47
47
  qty_diff = sim_qty - live_qty
48
48
  logger.info(
49
49
  f"Reducing position for {instrument.symbol}: {live_qty} -> {sim_qty} (diff: {qty_diff})"
@@ -78,7 +78,12 @@ class CsvSignalRestorer(ISignalRestorer):
78
78
 
79
79
  try:
80
80
  # Read the CSV file
81
- df = pd.read_csv(file_path)
81
+ try:
82
+ df = pd.read_csv(file_path)
83
+ except Exception as e:
84
+ logger.info(f"Could not read signal file {file_path}: {e}")
85
+ return {}
86
+
82
87
  if df.empty:
83
88
  logger.info(f"No signals found in {file_path}")
84
89
  return {}
@@ -181,7 +181,7 @@ def portfolio(all=True):
181
181
  d = dict()
182
182
  for s, p in ctx.get_positions().items():
183
183
  mv = round(p.market_value_funds, 3)
184
- if mv != 0.0 or all:
184
+ if p.quantity != 0.0 or all:
185
185
  d[dequotify(s.symbol)] = _pos_to_dict(p)
186
186
 
187
187
  d = pd.DataFrame.from_dict(d, orient='index')
@@ -232,14 +232,14 @@ class IntMagics(Magics):
232
232
 
233
233
  @line_cell_magic
234
234
  def lp(self, line: str):
235
- portfolio('true' in line)
235
+ portfolio(any(x in line.lower() for x in ['true', 'all']))
236
236
 
237
237
  @line_cell_magic
238
238
  def add(self, line: str):
239
239
  ctx + line.strip()
240
240
 
241
241
  @line_cell_magic
242
- def rm(self, line: str):
242
+ def remove(self, line: str):
243
243
  ctx - line.strip()
244
244
 
245
245
  @line_cell_magic
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