Qubx 0.6.42__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.42 → qubx-0.6.44}/PKG-INFO +1 -1
- {qubx-0.6.42 → qubx-0.6.44}/pyproject.toml +1 -1
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/utils.py +1 -1
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/lookups.py +2 -1
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/metrics.py +2 -2
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/mixins/universe.py +2 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/pandaz/ta.py +18 -5
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/pandaz/utils.py +15 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/balance.py +33 -18
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/position.py +34 -15
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/signal.py +30 -7
- {qubx-0.6.42 → qubx-0.6.44}/LICENSE +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/README.md +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/build.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/_nb_magic.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/account.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/broker.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/data.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/management.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/ome.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/optimization.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/runner.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/simulated_data.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/simulated_exchange.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/backtester/simulator.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/cli/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/cli/commands.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/cli/deploy.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/cli/misc.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/cli/release.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/account.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/broker.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/data.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/exceptions.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/factory.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/reader.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/ccxt/utils.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/tardis/data.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/connectors/tardis/utils.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/account.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/basics.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/context.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/deque.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/errors.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/exceptions.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/helpers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/initializer.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/interfaces.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/loggers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/mixins/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/mixins/market.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/mixins/processing.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/mixins/subscription.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/mixins/trading.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/series.pxd +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/series.pyi +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/series.pyx +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/utils.pyi +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/core/utils.pyx +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/data/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/data/composite.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/data/helpers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/data/hft.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/data/readers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/data/registry.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/data/tardis.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/emitters/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/emitters/base.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/emitters/composite.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/emitters/csv.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/emitters/prometheus.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/emitters/questdb.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/composite.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/formatters/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/formatters/base.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/formatters/incremental.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/formatters/slack.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/redis_streams.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/exporters/slack.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/features/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/features/core.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/features/orderbook.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/features/price.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/features/trades.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/features/utils.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/gathering/simplest.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/health/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/health/base.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/loggers/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/loggers/csv.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/loggers/factory.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/loggers/inmemory.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/loggers/mongo.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/math/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/math/stats.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/notifications/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/notifications/composite.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/notifications/slack.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/notifications/throttler.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/pandaz/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/_build.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-binance.cm.json +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-binance.json +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-binance.um.json +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-bitfinex.f.json +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-bitfinex.json +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-kraken.f.json +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/resources/instruments/symbols-kraken.json +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restarts/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restarts/state_resolvers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restarts/time_finders.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/factory.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/interfaces.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/state.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/restorers/utils.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/ta/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/ta/indicators.pxd +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/ta/indicators.pyi +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/ta/indicators.pyx +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/trackers/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/trackers/advanced.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/trackers/composite.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/trackers/rebalancers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/trackers/riskctrl.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/trackers/sizers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/_pyxreloader.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/charting/lookinglass.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/charting/mpl_helpers.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/collections.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/marketdata/binance.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/marketdata/ccxt.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/marketdata/dukas.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/misc.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/ntp.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/numbers_utils.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/orderbook.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/plotting/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/plotting/dashboard.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/plotting/data.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/plotting/interfaces.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/questdb.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/runner/__init__.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/runner/accounts.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/runner/configs.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/runner/factory.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/runner/runner.py +0 -0
- {qubx-0.6.42 → qubx-0.6.44}/src/qubx/utils/time.py +0 -0
- {qubx-0.6.42 → 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()
|
|
@@ -109,6 +109,8 @@ class UniverseManager(IUniverseManager):
|
|
|
109
109
|
if self._has_position(instr):
|
|
110
110
|
self._removal_queue[instr] = (if_has_position_then, skip_callback)
|
|
111
111
|
to_keep.append(instr)
|
|
112
|
+
else:
|
|
113
|
+
to_remove.append(instr)
|
|
112
114
|
return to_remove, to_keep
|
|
113
115
|
|
|
114
116
|
def __cleanup_removal_queue(self, instruments: list[Instrument]):
|
|
@@ -633,6 +633,17 @@ def rolling_std_with_mean(x: pd.Series, mean: float | pd.Series, window: int):
|
|
|
633
633
|
return np.sqrt((((x - mean) ** 2).rolling(window=window).sum() / (window - 1)))
|
|
634
634
|
|
|
635
635
|
|
|
636
|
+
def rolling_zscore(x: pd.Series, window: int):
|
|
637
|
+
"""
|
|
638
|
+
Calculates rolling z-score for data from x
|
|
639
|
+
:param x: series data
|
|
640
|
+
:param window: window
|
|
641
|
+
:return: rolling z-score
|
|
642
|
+
"""
|
|
643
|
+
r = x.rolling(window=window)
|
|
644
|
+
return (x - r.mean()) / r.std(ddof=0)
|
|
645
|
+
|
|
646
|
+
|
|
636
647
|
def bollinger(x: pd.Series, window=14, nstd=2, mean="sma") -> pd.DataFrame:
|
|
637
648
|
"""
|
|
638
649
|
Bollinger Bands indicator
|
|
@@ -1326,11 +1337,11 @@ def rolling_rank(x, period, pctls=(25, 50, 75)):
|
|
|
1326
1337
|
raise ValueError(f"Period {period} exceeds number of data records {len(x)} ")
|
|
1327
1338
|
|
|
1328
1339
|
if isinstance(x, pd.DataFrame):
|
|
1329
|
-
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()})
|
|
1330
1341
|
elif isinstance(x, pd.Series):
|
|
1331
|
-
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)
|
|
1332
1343
|
else:
|
|
1333
|
-
z = _rolling_rank(x
|
|
1344
|
+
z = _rolling_rank(np.ascontiguousarray(x), period, pctls)
|
|
1334
1345
|
return z
|
|
1335
1346
|
|
|
1336
1347
|
|
|
@@ -1532,6 +1543,7 @@ def choppiness(
|
|
|
1532
1543
|
volatility_estimator="t",
|
|
1533
1544
|
volume_adjusting=False,
|
|
1534
1545
|
identification="strong",
|
|
1546
|
+
with_raw_indicator=False,
|
|
1535
1547
|
) -> pd.Series:
|
|
1536
1548
|
"""
|
|
1537
1549
|
Calculate market choppiness index using volatility-based formula.
|
|
@@ -1566,7 +1578,8 @@ def choppiness(
|
|
|
1566
1578
|
0 when exiting trending regime (crossing above lower threshold)
|
|
1567
1579
|
- 'weak': Binary classification focused on choppiness - returns 1 when entering choppy regime (crossing above upper threshold),
|
|
1568
1580
|
0 when entering trending regime (crossing below lower threshold)
|
|
1569
|
-
|
|
1581
|
+
with_raw_indicator : bool, default False
|
|
1582
|
+
If True, returns the raw indicator value instead of the classification
|
|
1570
1583
|
Returns
|
|
1571
1584
|
-------
|
|
1572
1585
|
pd.Series
|
|
@@ -1619,7 +1632,7 @@ def choppiness(
|
|
|
1619
1632
|
# f0[(ci < lower) & (ci.shift(1) >= lower)] = 0
|
|
1620
1633
|
# return f0.ffill().fillna(0)
|
|
1621
1634
|
|
|
1622
|
-
return f0.ffill().fillna(0)
|
|
1635
|
+
return f0.ffill().fillna(0) if not with_raw_indicator else ci
|
|
1623
1636
|
|
|
1624
1637
|
|
|
1625
1638
|
@njit
|
|
@@ -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
|