Qubx 0.6.43__tar.gz → 0.6.44__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.
- {qubx-0.6.43 → qubx-0.6.44}/PKG-INFO +1 -1
- {qubx-0.6.43 → qubx-0.6.44}/pyproject.toml +1 -1
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/utils.py +1 -1
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/lookups.py +2 -1
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/metrics.py +2 -2
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/pandaz/ta.py +3 -3
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/pandaz/utils.py +15 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/balance.py +33 -18
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/position.py +34 -15
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/signal.py +30 -7
- {qubx-0.6.43 → qubx-0.6.44}/LICENSE +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/README.md +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/build.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/_nb_magic.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/account.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/broker.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/data.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/management.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/ome.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/optimization.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/runner.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/simulated_data.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/simulated_exchange.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/backtester/simulator.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/cli/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/cli/commands.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/cli/deploy.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/cli/misc.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/cli/release.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/account.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/broker.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/data.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/exceptions.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/factory.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/reader.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/ccxt/utils.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/tardis/data.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/connectors/tardis/utils.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/account.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/basics.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/context.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/deque.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/errors.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/exceptions.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/helpers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/initializer.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/interfaces.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/loggers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/mixins/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/mixins/market.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/mixins/processing.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/mixins/subscription.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/mixins/trading.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/mixins/universe.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/series.pxd +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/series.pyi +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/series.pyx +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/utils.pyi +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/core/utils.pyx +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/data/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/data/composite.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/data/helpers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/data/hft.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/data/readers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/data/registry.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/data/tardis.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/emitters/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/emitters/base.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/emitters/composite.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/emitters/csv.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/emitters/prometheus.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/emitters/questdb.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/composite.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/formatters/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/formatters/base.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/formatters/incremental.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/formatters/slack.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/redis_streams.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/exporters/slack.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/features/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/features/core.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/features/orderbook.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/features/price.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/features/trades.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/features/utils.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/gathering/simplest.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/health/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/health/base.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/loggers/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/loggers/csv.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/loggers/factory.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/loggers/inmemory.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/loggers/mongo.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/math/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/math/stats.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/notifications/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/notifications/composite.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/notifications/slack.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/notifications/throttler.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/pandaz/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/_build.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-binance.cm.json +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-binance.json +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-binance.um.json +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-bitfinex.f.json +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-bitfinex.json +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-kraken.f.json +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-kraken.json +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restarts/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restarts/state_resolvers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restarts/time_finders.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/factory.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/interfaces.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/state.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/restorers/utils.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/ta/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/ta/indicators.pxd +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/ta/indicators.pyi +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/ta/indicators.pyx +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/trackers/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/trackers/advanced.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/trackers/composite.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/trackers/rebalancers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/trackers/riskctrl.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/trackers/sizers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/_pyxreloader.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/charting/lookinglass.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/charting/mpl_helpers.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/collections.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/marketdata/binance.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/marketdata/ccxt.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/marketdata/dukas.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/misc.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/ntp.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/numbers_utils.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/orderbook.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/plotting/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/plotting/dashboard.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/plotting/data.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/plotting/interfaces.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/questdb.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/runner/__init__.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/runner/accounts.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/runner/configs.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/runner/factory.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/runner/runner.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/time.py +0 -0
- {qubx-0.6.43 → qubx-0.6.44}/src/qubx/utils/version.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "Qubx"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.44"
|
|
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"
|
|
@@ -218,7 +218,7 @@ def find_instruments_and_exchanges(
|
|
|
218
218
|
exchange: ExchangeName_t | None,
|
|
219
219
|
) -> tuple[list[Instrument], list[ExchangeName_t]]:
|
|
220
220
|
_instrs: list[Instrument] = []
|
|
221
|
-
_exchanges = [] if exchange is None else [exchange
|
|
221
|
+
_exchanges = [] if exchange is None else [exchange]
|
|
222
222
|
for i in instruments:
|
|
223
223
|
match i:
|
|
224
224
|
case str():
|
|
@@ -283,13 +283,14 @@ class InstrumentsLookup:
|
|
|
283
283
|
query_exchanges=query_exchanges,
|
|
284
284
|
)
|
|
285
285
|
|
|
286
|
+
#todo: temporaty disabled ccxt call to exchange, due to conectivity issues. Revert for bitfinex live usage
|
|
286
287
|
def _update_bitfinex(self, path: str, query_exchanges: bool = False):
|
|
287
288
|
self._ccxt_update(
|
|
288
289
|
path,
|
|
289
290
|
"bitfinex.f",
|
|
290
291
|
{"bitfinex.f": "bitfinex"},
|
|
291
292
|
keep_types=[MarketType.SWAP],
|
|
292
|
-
query_exchanges=
|
|
293
|
+
query_exchanges=False,
|
|
293
294
|
)
|
|
294
295
|
|
|
295
296
|
def _update_bitmex(self, path: str, query_exchanges: bool = False):
|
|
@@ -1406,8 +1406,8 @@ def chart_signals(
|
|
|
1406
1406
|
if show_leverage:
|
|
1407
1407
|
leverage = calculate_leverage(portfolio, result.capital, start, symbol)
|
|
1408
1408
|
indicators["Leverage"] = ["area", "cyan", leverage]
|
|
1409
|
-
symbol_count = len(portfolio.filter(like="_PnL").columns)
|
|
1410
|
-
pnl = portfolio.filter(regex=f"{symbol}_PnL").cumsum() + result.capital / symbol_count
|
|
1409
|
+
# symbol_count = len(portfolio.filter(like="_PnL").columns)
|
|
1410
|
+
pnl = portfolio.filter(regex=f"{symbol}_PnL").cumsum() + result.capital # / symbol_count
|
|
1411
1411
|
pnl = pnl.loc[start:]
|
|
1412
1412
|
if apply_commissions:
|
|
1413
1413
|
comm = portfolio.filter(regex=f"{symbol}_Commissions").loc[start:].cumsum()
|
|
@@ -1337,11 +1337,11 @@ def rolling_rank(x, period, pctls=(25, 50, 75)):
|
|
|
1337
1337
|
raise ValueError(f"Period {period} exceeds number of data records {len(x)} ")
|
|
1338
1338
|
|
|
1339
1339
|
if isinstance(x, pd.DataFrame):
|
|
1340
|
-
z = pd.DataFrame.from_dict({c: rolling_rank(s, period, pctls) for c, s in x.
|
|
1340
|
+
z = pd.DataFrame.from_dict({c: rolling_rank(s, period, pctls) for c, s in x.items()})
|
|
1341
1341
|
elif isinstance(x, pd.Series):
|
|
1342
|
-
z = pd.Series(_rolling_rank(x.values, period, pctls), x.index, name=x.name)
|
|
1342
|
+
z = pd.Series(_rolling_rank(np.ascontiguousarray(x.values), period, pctls), x.index, name=x.name)
|
|
1343
1343
|
else:
|
|
1344
|
-
z = _rolling_rank(x
|
|
1344
|
+
z = _rolling_rank(np.ascontiguousarray(x), period, pctls)
|
|
1345
1345
|
return z
|
|
1346
1346
|
|
|
1347
1347
|
|
|
@@ -590,9 +590,11 @@ class OhlcDict(dict):
|
|
|
590
590
|
print(str(d))
|
|
591
591
|
"""
|
|
592
592
|
|
|
593
|
+
_orig: dict[str, pd.DataFrame | pd.Series | OHLCV]
|
|
593
594
|
_fields: Set[str]
|
|
594
595
|
|
|
595
596
|
def __init__(self, orig: dict[str, pd.DataFrame | pd.Series | OHLCV]):
|
|
597
|
+
self._orig = orig
|
|
596
598
|
_o_copy = {}
|
|
597
599
|
_lst = []
|
|
598
600
|
if isinstance(orig, dict):
|
|
@@ -639,3 +641,16 @@ class OhlcDict(dict):
|
|
|
639
641
|
|
|
640
642
|
def __repr__(self) -> str:
|
|
641
643
|
return self.display(3, 3)
|
|
644
|
+
|
|
645
|
+
def __reduce__(self):
|
|
646
|
+
"""
|
|
647
|
+
For joblib Parallel compatibility - defines how to pickle the object
|
|
648
|
+
"""
|
|
649
|
+
# Return the class, constructor arguments, and additional state
|
|
650
|
+
data = {k: v for k, v in self.items()}
|
|
651
|
+
return (self.__class__, (data,), {"_orig": self._orig})
|
|
652
|
+
|
|
653
|
+
def __setstate__(self, state):
|
|
654
|
+
"""Restore object from pickle state"""
|
|
655
|
+
# Recreate the object using the constructor
|
|
656
|
+
self.__init__(state["_orig"])
|
|
@@ -8,6 +8,7 @@ from various sources.
|
|
|
8
8
|
import os
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from pymongo import MongoClient
|
|
11
|
+
from datetime import datetime, timedelta
|
|
11
12
|
|
|
12
13
|
import pandas as pd
|
|
13
14
|
|
|
@@ -152,13 +153,16 @@ class MongoDBBalanceRestorer(IBalanceRestorer):
|
|
|
152
153
|
Example: {'USDT': AssetBalance(total=100000.0, locked=0.0)}
|
|
153
154
|
"""
|
|
154
155
|
try:
|
|
155
|
-
|
|
156
|
+
now = datetime.utcnow()
|
|
157
|
+
lookup_range = now - timedelta(days=7)
|
|
158
|
+
base_match = {
|
|
156
159
|
"log_type": "balance",
|
|
157
160
|
"strategy_name": self.strategy_name,
|
|
161
|
+
"timestamp": {"$gte": lookup_range}
|
|
158
162
|
}
|
|
159
163
|
|
|
160
164
|
latest_run_doc = (
|
|
161
|
-
self.collection.find(
|
|
165
|
+
self.collection.find(base_match, {"run_id": 1, "timestamp": 1})
|
|
162
166
|
.sort("timestamp", -1)
|
|
163
167
|
.limit(1)
|
|
164
168
|
)
|
|
@@ -172,23 +176,34 @@ class MongoDBBalanceRestorer(IBalanceRestorer):
|
|
|
172
176
|
|
|
173
177
|
logger.info(f"Restoring balances from MongoDB for run_id: {latest_run_id}")
|
|
174
178
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
pipeline = [
|
|
180
|
+
{"$match": {**base_match, "run_id": latest_run_id}},
|
|
181
|
+
{"$sort": {"timestamp": -1}},
|
|
182
|
+
{
|
|
183
|
+
"$group": {
|
|
184
|
+
"_id": "$currency",
|
|
185
|
+
"doc": {"$first": "$$ROOT"}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
cursor = self.collection.aggregate(pipeline)
|
|
191
|
+
balances: dict[str, AssetBalance] = {}
|
|
192
|
+
|
|
193
|
+
for entry in cursor:
|
|
194
|
+
log = entry["doc"]
|
|
181
195
|
currency = log.get("currency")
|
|
182
|
-
if currency:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
if not currency:
|
|
197
|
+
continue
|
|
198
|
+
total = log.get("total", 0.0)
|
|
199
|
+
locked = log.get("locked", 0.0)
|
|
200
|
+
|
|
201
|
+
balance = AssetBalance(
|
|
202
|
+
total=total,
|
|
203
|
+
locked=locked,
|
|
204
|
+
)
|
|
205
|
+
balance.free = total - locked
|
|
206
|
+
balances[currency] = balance
|
|
192
207
|
|
|
193
208
|
return balances
|
|
194
209
|
except Exception as e:
|
|
@@ -8,6 +8,7 @@ for restoring positions from various sources.
|
|
|
8
8
|
import os
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from pymongo import MongoClient
|
|
11
|
+
from datetime import datetime, timedelta
|
|
11
12
|
|
|
12
13
|
import pandas as pd
|
|
13
14
|
|
|
@@ -168,13 +169,17 @@ class MongoDBPositionRestorer(IPositionRestorer):
|
|
|
168
169
|
A dictionary mapping instruments to positions.
|
|
169
170
|
"""
|
|
170
171
|
try:
|
|
171
|
-
|
|
172
|
+
now = datetime.utcnow()
|
|
173
|
+
lookup_range = now - timedelta(days=7)
|
|
174
|
+
|
|
175
|
+
base_match = {
|
|
172
176
|
"log_type": "positions",
|
|
173
177
|
"strategy_name": self.strategy_name,
|
|
178
|
+
"timestamp": {"$gte": lookup_range}
|
|
174
179
|
}
|
|
175
180
|
|
|
176
181
|
latest_run_doc = (
|
|
177
|
-
self.collection.find(
|
|
182
|
+
self.collection.find(base_match, {"run_id": 1, "timestamp": 1})
|
|
178
183
|
.sort("timestamp", -1)
|
|
179
184
|
.limit(1)
|
|
180
185
|
)
|
|
@@ -188,20 +193,34 @@ class MongoDBPositionRestorer(IPositionRestorer):
|
|
|
188
193
|
|
|
189
194
|
logger.info(f"Restoring positions from MongoDB for run_id: {latest_run_id}")
|
|
190
195
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
pipeline = [
|
|
197
|
+
{"$match": {**base_match, "run_id": latest_run_id}},
|
|
198
|
+
{"$sort": {"timestamp": -1}},
|
|
199
|
+
{
|
|
200
|
+
"$group": {
|
|
201
|
+
"_id": {
|
|
202
|
+
"symbol": "$symbol",
|
|
203
|
+
"exchange": "$exchange",
|
|
204
|
+
"market_type": "$market_type"
|
|
205
|
+
},
|
|
206
|
+
"doc": {"$first": "$$ROOT"}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
cursor = self.collection.aggregate(pipeline)
|
|
212
|
+
|
|
213
|
+
positions: dict[Instrument, Position] = {}
|
|
214
|
+
|
|
215
|
+
for entry in cursor:
|
|
216
|
+
log = entry["doc"]
|
|
217
|
+
|
|
218
|
+
symbol = log.get("symbol")
|
|
219
|
+
exchange = log.get("exchange")
|
|
220
|
+
market_type = log.get("market_type")
|
|
221
|
+
|
|
222
|
+
if not (symbol and exchange and market_type):
|
|
200
223
|
continue
|
|
201
|
-
seen_keys.add(key)
|
|
202
|
-
|
|
203
|
-
symbol = log["symbol"]
|
|
204
|
-
exchange = log["exchange"]
|
|
205
224
|
|
|
206
225
|
instrument = lookup.find_symbol(exchange, symbol)
|
|
207
226
|
if instrument is None:
|
|
@@ -208,13 +208,16 @@ class MongoDBSignalRestorer(ISignalRestorer):
|
|
|
208
208
|
A dictionary mapping instruments to lists of signals.
|
|
209
209
|
"""
|
|
210
210
|
try:
|
|
211
|
-
|
|
211
|
+
now = datetime.utcnow()
|
|
212
|
+
lookup_range = now - timedelta(days=30)
|
|
213
|
+
base_match = {
|
|
212
214
|
"log_type": "signals",
|
|
213
215
|
"strategy_name": self.strategy_name,
|
|
216
|
+
"timestamp": {"$gte": lookup_range}
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
latest_run_doc = (
|
|
217
|
-
self.collection.find(
|
|
220
|
+
self.collection.find(base_match, {"run_id": 1, "timestamp": 1})
|
|
218
221
|
.sort("timestamp", -1)
|
|
219
222
|
.limit(1)
|
|
220
223
|
)
|
|
@@ -228,12 +231,33 @@ class MongoDBSignalRestorer(ISignalRestorer):
|
|
|
228
231
|
|
|
229
232
|
logger.info(f"Restoring signals from MongoDB for run_id: {latest_run_id}")
|
|
230
233
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
+
pipeline = [
|
|
235
|
+
{"$match": {"log_type": "signals", "strategy_name": self.strategy_name, "run_id": latest_run_id}},
|
|
236
|
+
{"$sort": {"timestamp": -1}},
|
|
237
|
+
{
|
|
238
|
+
"$group": {
|
|
239
|
+
"_id": {
|
|
240
|
+
"symbol": "$symbol",
|
|
241
|
+
"exchange": "$exchange",
|
|
242
|
+
"market_type": "$market_type",
|
|
243
|
+
},
|
|
244
|
+
"signals": {"$push": "$$ROOT"}
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"$project": {
|
|
249
|
+
"signals": {"$slice": ["$signals", 20]}
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{"$unwind": "$signals"}
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
cursor = self.collection.aggregate(pipeline)
|
|
256
|
+
|
|
234
257
|
result: dict[Instrument, list[TargetPosition]] = {}
|
|
235
258
|
|
|
236
|
-
for
|
|
259
|
+
for entry in cursor:
|
|
260
|
+
log = entry["signals"]
|
|
237
261
|
try:
|
|
238
262
|
instrument = lookup.find_symbol(log["exchange"], log["symbol"])
|
|
239
263
|
if instrument is None:
|
|
@@ -281,7 +305,6 @@ class MongoDBSignalRestorer(ISignalRestorer):
|
|
|
281
305
|
)
|
|
282
306
|
|
|
283
307
|
result.setdefault(instrument, []).append(target_position)
|
|
284
|
-
|
|
285
308
|
except Exception as e:
|
|
286
309
|
logger.exception(f"Failed to process signal document: {e}")
|
|
287
310
|
|
|
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
|
|
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
|
|
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
|