Qubx 0.2.76__tar.gz → 0.2.78__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 (57) hide show
  1. {qubx-0.2.76 → qubx-0.2.78}/PKG-INFO +2 -2
  2. {qubx-0.2.76 → qubx-0.2.78}/pyproject.toml +2 -2
  3. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/backtester/simulator.py +2 -0
  4. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/basics.py +5 -0
  5. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/lookups.py +1 -1
  6. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/strategy.py +1 -0
  7. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/data/readers.py +6 -3
  8. {qubx-0.2.76 → qubx-0.2.78}/README.md +0 -0
  9. {qubx-0.2.76 → qubx-0.2.78}/build.py +0 -0
  10. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/__init__.py +0 -0
  11. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/_nb_magic.py +0 -0
  12. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/backtester/__init__.py +0 -0
  13. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/backtester/ome.py +0 -0
  14. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/backtester/optimization.py +0 -0
  15. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/backtester/queue.py +0 -0
  16. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/__init__.py +0 -0
  17. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/account.py +0 -0
  18. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/context.py +0 -0
  19. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/exceptions.py +0 -0
  20. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/helpers.py +0 -0
  21. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/loggers.py +0 -0
  22. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/metrics.py +0 -0
  23. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/series.pxd +0 -0
  24. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/series.pyi +0 -0
  25. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/series.pyx +0 -0
  26. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/utils.pyi +0 -0
  27. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/core/utils.pyx +0 -0
  28. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/data/__init__.py +0 -0
  29. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/data/helpers.py +0 -0
  30. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/gathering/simplest.py +0 -0
  31. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/impl/ccxt_connector.py +0 -0
  32. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/impl/ccxt_customizations.py +0 -0
  33. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/impl/ccxt_trading.py +0 -0
  34. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/impl/ccxt_utils.py +0 -0
  35. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/math/__init__.py +0 -0
  36. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/math/stats.py +0 -0
  37. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/pandaz/__init__.py +0 -0
  38. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/pandaz/ta.py +0 -0
  39. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/pandaz/utils.py +0 -0
  40. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/ta/__init__.py +0 -0
  41. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/ta/indicators.pxd +0 -0
  42. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/ta/indicators.pyi +0 -0
  43. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/ta/indicators.pyx +0 -0
  44. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/trackers/__init__.py +0 -0
  45. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/trackers/composite.py +0 -0
  46. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/trackers/rebalancers.py +0 -0
  47. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/trackers/riskctrl.py +0 -0
  48. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/trackers/sizers.py +0 -0
  49. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/__init__.py +0 -0
  50. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/_pyxreloader.py +0 -0
  51. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/charting/lookinglass.py +0 -0
  52. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/charting/mpl_helpers.py +0 -0
  53. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/marketdata/binance.py +0 -0
  54. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/misc.py +0 -0
  55. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/ntp.py +0 -0
  56. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/runner.py +0 -0
  57. {qubx-0.2.76 → qubx-0.2.78}/src/qubx/utils/time.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: Qubx
3
- Version: 0.2.76
3
+ Version: 0.2.78
4
4
  Summary: Qubx - quantitative trading framework
5
5
  Home-page: https://github.com/dmarienko/Qubx
6
6
  Author: Dmitry Marienko
@@ -25,7 +25,7 @@ Requires-Dist: psycopg (>=3.1.18,<4.0.0)
25
25
  Requires-Dist: psycopg-binary (>=3.1.19,<4.0.0)
26
26
  Requires-Dist: psycopg-pool (>=3.2.2,<4.0.0)
27
27
  Requires-Dist: pyarrow (>=15.0.0,<16.0.0)
28
- Requires-Dist: pydantic (>=1.10.2,<2.0.0)
28
+ Requires-Dist: pydantic (>=2.9.2,<3.0.0)
29
29
  Requires-Dist: pymongo (>=4.6.1,<5.0.0)
30
30
  Requires-Dist: pytest[lazyfixture] (>=7.2.0,<8.0.0)
31
31
  Requires-Dist: python-binance (>=1.0.19,<2.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "Qubx"
3
- version = "0.2.76"
3
+ version = "0.2.78"
4
4
  description = "Qubx - quantitative trading framework"
5
5
  authors = ["Dmitry Marienko <dmitry@gmail.com>", "Yuriy Arabskyy <yuriy.arabskyy@gmail.com>"]
6
6
  readme = "README.md"
@@ -24,7 +24,7 @@ tqdm = "*"
24
24
  importlib-metadata = "*"
25
25
  stackprinter = "^0.2.10"
26
26
  pymongo = "^4.6.1"
27
- pydantic = "^1.10.2"
27
+ pydantic = "^2.9.2"
28
28
  python-dotenv = "^1.0.0"
29
29
  python-binance = "^1.0.19"
30
30
  pyarrow = "^15.0.0"
@@ -589,6 +589,8 @@ class SimulatedExchange(IBrokerServiceProvider):
589
589
  records = self._reader.read(
590
590
  data_id=_spec, start=start, stop=end, transform=AsTimestampedRecords() # type: ignore
591
591
  )
592
+ if not records:
593
+ return []
592
594
  return [
593
595
  Bar(np.datetime64(r["timestamp_ns"], "ns").item(), r["open"], r["high"], r["low"], r["close"], r["volume"])
594
596
  for r in records
@@ -417,8 +417,12 @@ class Position:
417
417
 
418
418
  # - extract realized part of PnL
419
419
  if qty_closing != 0:
420
+ _abs_qty_close = abs(qty_closing)
420
421
  deal_pnl = qty_closing * (self.position_avg_price - exec_price)
422
+
421
423
  quantity += qty_closing
424
+ self.__pos_incr_qty -= _abs_qty_close
425
+
422
426
  # - reset average price to 0 if smaller than minimal price change to avoid cumulative error
423
427
  if abs(quantity) < self.instrument.min_size_step:
424
428
  quantity = 0.0
@@ -480,6 +484,7 @@ class Position:
480
484
  return self.pnl
481
485
 
482
486
  def total_pnl(self) -> float:
487
+ # TODO: account for commissions
483
488
  pnl = self.r_pnl
484
489
  if not np.isnan(self.last_update_price): # type: ignore
485
490
  pnl += self.quantity * (self.last_update_price - self.position_avg_price) / self.last_update_conversion_rate # type: ignore
@@ -410,7 +410,7 @@ class GlobalLookup:
410
410
  instruments: InstrumentsLookup
411
411
  fees: FeesLookup
412
412
 
413
- def find_fees(self, exchange: str, spec: str) -> Optional[TransactionCostsCalculator]:
413
+ def find_fees(self, exchange: str, spec: str | None) -> Optional[TransactionCostsCalculator]:
414
414
  return self.fees.find(exchange, spec)
415
415
 
416
416
  def find_aux_instrument_for(self, instrument: Instrument, base_currency: str) -> Optional[Instrument]:
@@ -154,6 +154,7 @@ class StrategyContext(ITimeProvider):
154
154
  instruments: List[Instrument] # list of instruments this strategy trades
155
155
  positions: Dict[str, Position] # positions of the strategy (instrument -> position)
156
156
  acc: AccountProcessor
157
+ broker_provider: IBrokerServiceProvider # market data provider
157
158
 
158
159
  def process_data(self, symbol: str, d_type: str, data: Any) -> bool: ...
159
160
 
@@ -907,7 +907,7 @@ class QuestDBConnector(DataReader):
907
907
 
908
908
  query = f"""
909
909
  select timestamp,
910
- symbol,
910
+ upper(symbol) as symbol,
911
911
  first(open) as open,
912
912
  max(high) as high,
913
913
  min(low) as low,
@@ -919,7 +919,10 @@ class QuestDBConnector(DataReader):
919
919
  sum(taker_buy_quote_volume) as taker_buy_quote_volume
920
920
  from "{table_name}" {where} {_rsmpl};
921
921
  """
922
- return self.execute(query).set_index(["timestamp", "symbol"])
922
+ res = self.execute(query)
923
+ if res.empty:
924
+ return res
925
+ return res.set_index(["timestamp", "symbol"])
923
926
 
924
927
  def get_average_quote_volume(
925
928
  self,
@@ -936,7 +939,7 @@ class QuestDBConnector(DataReader):
936
939
  where timestamp >= '{start}' and timestamp < '{stop}'
937
940
  SAMPLE BY {QuestDBSqlCandlesBuilder._convert_time_delta_to_qdb_resample_format(timeframe)}
938
941
  )
939
- select symbol, avg(qvolume) as quote_volume from sampled
942
+ select upper(symbol) as symbol, avg(qvolume) as quote_volume from sampled
940
943
  group by symbol
941
944
  order by quote_volume desc;
942
945
  """
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