Qubx 1.2.2.dev2__tar.gz → 1.2.3.dev1__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.
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/PKG-INFO +1 -1
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/_version.py +2 -2
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/okx/account.py +55 -4
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/account.py +4 -1
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/loggers.py +39 -23
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/utils.pyx +6 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/configs.py +3 -2
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/runner.py +1 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/.gitignore +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/LICENSE +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/README.md +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/pyproject.toml +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/scripts/build.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/_nb_magic.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/account.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/broker.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/data.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/iteratedstream.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/management.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/ome.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/optimization.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/runner.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/sentinels.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/simulated_data.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/simulated_exchange.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/simulator.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/transfers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/backtester/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/commands.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/deploy.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/misc.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/release.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/resolver.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/s3.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/theme.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/tui.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/cli/user_config.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/config.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/account.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/adapters/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/adapters/polling_adapter.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/broker.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/connection_manager.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/data.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exceptions.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchange_manager.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/base.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/binance/broker.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/binance/exchange.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/gateio/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/gateio/gateio.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/account.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/broker.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/kraken/kraken.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/okx/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/okx/broker.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/okx/okx.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/factory.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/base.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/factory.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/funding_rate.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/liquidation.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/ohlc.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/open_interest.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/orderbook.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/quote.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/handlers/trade.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/rate_limits.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/subscription_config.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/subscription_manager.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/subscription_orchestrator.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/warmup_service.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/registry.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/tardis/data.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/tardis/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/control/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/control/builtin.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/control/decorator.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/control/executor.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/control/interfaces.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/control/server.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/control/types.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/basics.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/context.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/detectors/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/detectors/delisting.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/detectors/stale.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/errors.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/exceptions.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/helpers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/initializer.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/interfaces.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/lookups.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/metrics.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/mixins/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/mixins/market.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/mixins/processing.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/mixins/subscription.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/mixins/trading.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/mixins/universe.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/mixins/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/series.pxd +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/series.pyi +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/series.pyx +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/core/utils.pyi +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/cache.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/containers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/guards.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/registry.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storage.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storages/ccxt.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storages/csv.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storages/handy.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storages/multi.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storages/questdb.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storages/stub.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/storages/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/data/transformers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/base.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/composite.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/csv.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/indicator.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/inmemory.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/prometheus.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/emitters/questdb.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/composite.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/formatters/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/formatters/base.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/formatters/incremental.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/formatters/slack.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/formatters/target_position.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/redis_streams.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/exporters/slack.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/gathering/simplest.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/health/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/health/base.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/health/dummy.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/loggers/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/loggers/csv.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/loggers/factory.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/loggers/inmemory.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/loggers/mongo.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/loggers/postgres.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/notifications/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/notifications/composite.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/notifications/slack.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/notifications/throttler.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/pandaz/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/pandaz/stats.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/pandaz/ta.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/pandaz/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/plugins/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/plugins/loader.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/backend.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/config.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/engine.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/ip_resolver.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/manager.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/pools.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/rate_limiting/redis_backend.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/_build.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/crypto-fees.ini +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/hyperliquid-spot.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/hyperliquid.f-perpetual.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-binance-spot.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-binance.cm-future.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-binance.cm-perpetual.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-binance.um-future.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-binance.um-perpetual.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-bitfinex.f-perpetual.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-kraken-spot.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-kraken.f-future.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/resources/instruments/symbols-kraken.f-perpetual.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restarts/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restarts/state_resolvers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restarts/time_finders.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/balance.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/factory.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/interfaces.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/position.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/signal.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/state.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/restorers/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/state/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/state/dummy.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/state/redis.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/ta/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/ta/indicators.pxd +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/ta/indicators.pyi +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/ta/indicators.pyx +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/base.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/accounts.toml.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/config.yml.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/jlive.sh.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/jpaper.sh.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/pyproject.toml.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/src/{{ strategy_name }}/__init__.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/src/{{ strategy_name }}/strategy.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/project/template.yml +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.claude/skills/qubx-cli/SKILL.md +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.claude/skills/qubx-indicators/SKILL.md +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.claude/skills/simulation-explorer/SKILL.md +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.claude/skills/strategy-release/SKILL.md +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.github/workflows/ci.yml.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.gitignore.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.python-version +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.vscode/launch.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.vscode/settings.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/.vscode/tasks.json +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/CLAUDE.md.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/README.md.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/configs/.gitkeep +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/justfile.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/pyproject.toml.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/research/.gitkeep +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/src/{{ strategy_name }}/__init__.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/src/{{ strategy_name }}/cli.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/src/{{ strategy_name }}/strategy.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/template.yml +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/repo/tests/test_strategy.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/simple/__init__.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/simple/accounts.toml.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/simple/config.yml.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/simple/jlive.sh.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/simple/jpaper.sh.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/simple/strategy.py.j2 +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/templates/simple/template.yml +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/trackers/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/trackers/advanced.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/trackers/composite.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/trackers/rebalancers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/trackers/riskctrl.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/trackers/sizers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/_pyxreloader.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/charting/lookinglass.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/charting/mpl_helpers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/charting/orderbook.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/collections.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/hft/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/hft/numba_utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/hft/orderbook.pyi +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/hft/orderbook.pyx +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/marketdata/binance.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/marketdata/ccxt.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/marketdata/dukas.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/misc.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/nonce.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/ntp.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/numbers_utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/orderbook.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/plotting/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/plotting/dashboard.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/plotting/data.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/plotting/interfaces.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/plotting/renderers/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/plotting/renderers/plotly.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/questdb.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/rate_limiter.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/results.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/ringbuffer.pxd +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/ringbuffer.pyi +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/ringbuffer.pyx +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/_jupyter_runner.pyt +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/accounts.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/factory.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/kernel_service.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/app.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/handlers.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/init_code.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/kernel.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/styles.tcss +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/__init__.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/account_summary.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/command_input.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/debug_log.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/orders_table.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/positions_table.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/quotes_table.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/runner/textual/widgets/repl_output.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/s3.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/slack.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/throttler.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/time.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/utils/websocket_manager.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/tests/strategies/macd_crossover/src/macd_crossover/indicators/macd.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/tests/strategies/macd_crossover/src/macd_crossover/models/macd_crossover.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/tests/strategies/macd_crossover/src/macd_crossover/models/utils.py +0 -0
- {qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/tests/strategies/obi_trader/src/obi_trader/models/obi_trader.py +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 2,
|
|
21
|
+
__version__ = version = '1.2.3.dev1'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 2, 3, 'dev1')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -18,8 +18,35 @@ class OkxAccountProcessor(CcxtAccountProcessor):
|
|
|
18
18
|
so we must subscribe to both channels separately:
|
|
19
19
|
- orders channel: for order status updates (watch_orders)
|
|
20
20
|
- trades channel: for trade/fill updates (watch_my_trades)
|
|
21
|
+
|
|
22
|
+
Balance streaming: uses watch_balance WS to get real-time totalEq updates
|
|
23
|
+
instead of relying solely on 30s polling.
|
|
21
24
|
"""
|
|
22
25
|
|
|
26
|
+
def start(self):
|
|
27
|
+
super().start()
|
|
28
|
+
if self._is_running and not self.exchange_manager.exchange.isSandboxModeEnabled:
|
|
29
|
+
self._polling_tasks["balance_ws"] = self._loop.submit(self._watch_balance_stream())
|
|
30
|
+
|
|
31
|
+
async def _watch_balance_stream(self):
|
|
32
|
+
"""Stream balance updates via WS to get real-time totalEq."""
|
|
33
|
+
|
|
34
|
+
async def _watch():
|
|
35
|
+
balances_raw = await self.exchange_manager.exchange.watch_balance()
|
|
36
|
+
equity = self._extract_portfolio_value(balances_raw)
|
|
37
|
+
if equity is not None:
|
|
38
|
+
self._exchange_total_capital = equity
|
|
39
|
+
margin_ratio = self._extract_margin_ratio(balances_raw)
|
|
40
|
+
if margin_ratio is not None:
|
|
41
|
+
self._exchange_margin_ratio = margin_ratio
|
|
42
|
+
|
|
43
|
+
await self._listen_to_stream(
|
|
44
|
+
subscriber=_watch,
|
|
45
|
+
exchange=self.exchange_manager.exchange,
|
|
46
|
+
channel=self.channel,
|
|
47
|
+
name="okx_balance_ws",
|
|
48
|
+
)
|
|
49
|
+
|
|
23
50
|
async def _subscribe_executions(self, name: str, channel: CtrlChannel):
|
|
24
51
|
logger.info("<yellow>[OKX]</yellow> Subscribing to executions (orders + trades)")
|
|
25
52
|
_symbol_to_instrument = {}
|
|
@@ -57,11 +84,31 @@ class OkxAccountProcessor(CcxtAccountProcessor):
|
|
|
57
84
|
),
|
|
58
85
|
)
|
|
59
86
|
|
|
87
|
+
def _get_account_data(self, balances_raw: dict) -> dict:
|
|
88
|
+
"""Get the OKX account data dict from info.data[0]."""
|
|
89
|
+
return balances_raw.get("info", {}).get("data", [{}])[0]
|
|
90
|
+
|
|
91
|
+
def _extract_margin_ratio(self, balances_raw: dict) -> float | None:
|
|
92
|
+
"""Extract OKX margin ratio from the base currency detail entry.
|
|
93
|
+
|
|
94
|
+
The account-level mgnRatio is empty; the real value is per-currency in details.
|
|
95
|
+
We use the base currency's mgnRatio as the account margin ratio.
|
|
96
|
+
"""
|
|
97
|
+
details = self._get_account_data(balances_raw).get("details", [])
|
|
98
|
+
for detail in details:
|
|
99
|
+
if detail.get("ccy", "").upper() == self.base_currency.upper():
|
|
100
|
+
val = detail.get("mgnRatio")
|
|
101
|
+
if val is not None and val != "":
|
|
102
|
+
try:
|
|
103
|
+
return float(val)
|
|
104
|
+
except (ValueError, TypeError):
|
|
105
|
+
pass
|
|
106
|
+
return None
|
|
107
|
+
|
|
60
108
|
def _extract_portfolio_value(self, balances_raw: dict) -> float | None:
|
|
61
|
-
"""Extract OKX total equity from
|
|
62
|
-
|
|
63
|
-
total_eq
|
|
64
|
-
if total_eq is not None:
|
|
109
|
+
"""Extract OKX total equity from info.data[0].totalEq."""
|
|
110
|
+
total_eq = self._get_account_data(balances_raw).get("totalEq")
|
|
111
|
+
if total_eq is not None and total_eq != "":
|
|
65
112
|
try:
|
|
66
113
|
return float(total_eq)
|
|
67
114
|
except (ValueError, TypeError):
|
|
@@ -81,6 +128,10 @@ class OkxAccountProcessor(CcxtAccountProcessor):
|
|
|
81
128
|
if equity is not None:
|
|
82
129
|
self._exchange_total_capital = equity
|
|
83
130
|
|
|
131
|
+
margin_ratio = self._extract_margin_ratio(balances_raw)
|
|
132
|
+
if margin_ratio is not None:
|
|
133
|
+
self._exchange_margin_ratio = margin_ratio
|
|
134
|
+
|
|
84
135
|
# Extract cashBal from raw OKX response instead of CCXT-parsed eq
|
|
85
136
|
balances: list[AssetBalance] = []
|
|
86
137
|
raw_details = balances_raw.get("info", {}).get("data", [{}])[0].get("details", [])
|
|
@@ -66,6 +66,7 @@ class BasicAccountProcessor(IAccountProcessor):
|
|
|
66
66
|
self._pending_order_requests = {}
|
|
67
67
|
self._balances = {}
|
|
68
68
|
self._exchange_total_capital: float | None = None
|
|
69
|
+
self._exchange_margin_ratio: float | None = None
|
|
69
70
|
# Initialize with base currency balance
|
|
70
71
|
self._balances[self.base_currency] = AssetBalance(
|
|
71
72
|
exchange=self.exchange, currency=self.base_currency, free=initial_capital, locked=0.0, total=initial_capital
|
|
@@ -183,7 +184,9 @@ class BasicAccountProcessor(IAccountProcessor):
|
|
|
183
184
|
return self.get_total_capital(exchange) - self.get_total_required_margin(exchange)
|
|
184
185
|
|
|
185
186
|
def get_margin_ratio(self, exchange: str | None = None) -> float:
|
|
186
|
-
|
|
187
|
+
if self._exchange_margin_ratio is not None:
|
|
188
|
+
return self._exchange_margin_ratio
|
|
189
|
+
# fallback: total capital / total required margin
|
|
187
190
|
required_margin = self.get_total_required_margin(exchange)
|
|
188
191
|
if required_margin == 0:
|
|
189
192
|
return 100.0
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
6
7
|
|
|
7
8
|
from qubx import logger
|
|
8
9
|
from qubx.core.basics import (
|
|
@@ -100,28 +101,35 @@ class PositionsDumper(_BaseIntervalDumper):
|
|
|
100
101
|
self.positions[p.instrument] = p
|
|
101
102
|
return self
|
|
102
103
|
|
|
104
|
+
@staticmethod
|
|
105
|
+
def _position_row(instrument: Instrument, position: Position, timestamp: np.datetime64) -> dict[str, Any]:
|
|
106
|
+
return {
|
|
107
|
+
"timestamp": str(timestamp),
|
|
108
|
+
"symbol": instrument.symbol,
|
|
109
|
+
"exchange": instrument.exchange,
|
|
110
|
+
"market_type": instrument.market_type,
|
|
111
|
+
"pnl_quoted": position.pnl,
|
|
112
|
+
"funding_pnl_quoted": position.cumulative_funding,
|
|
113
|
+
"realized_pnl_quoted": position.r_pnl,
|
|
114
|
+
"quantity": position.quantity,
|
|
115
|
+
"notional": position.notional_value,
|
|
116
|
+
"avg_position_price": position.position_avg_price if position.quantity != 0.0 else 0.0,
|
|
117
|
+
"current_price": position.last_update_price,
|
|
118
|
+
"market_value_quoted": position.market_value_funds,
|
|
119
|
+
"commissions_quoted": position.commissions,
|
|
120
|
+
}
|
|
121
|
+
|
|
103
122
|
def dump(self, interval_start_time: np.datetime64, actual_timestamp: np.datetime64):
|
|
104
|
-
data = []
|
|
105
|
-
for i, p in self.positions.items():
|
|
106
|
-
data.append(
|
|
107
|
-
{
|
|
108
|
-
"timestamp": str(actual_timestamp),
|
|
109
|
-
"symbol": i.symbol,
|
|
110
|
-
"exchange": i.exchange,
|
|
111
|
-
"market_type": i.market_type,
|
|
112
|
-
"pnl_quoted": p.pnl,
|
|
113
|
-
"funding_pnl_quoted": p.cumulative_funding,
|
|
114
|
-
"realized_pnl_quoted": p.r_pnl,
|
|
115
|
-
"quantity": p.quantity,
|
|
116
|
-
"notional": p.notional_value,
|
|
117
|
-
"avg_position_price": p.position_avg_price if p.quantity != 0.0 else 0.0,
|
|
118
|
-
"current_price": p.last_update_price,
|
|
119
|
-
"market_value_quoted": p.market_value_funds,
|
|
120
|
-
"commissions_quoted": p.commissions,
|
|
121
|
-
}
|
|
122
|
-
)
|
|
123
|
+
data = [self._position_row(i, p, actual_timestamp) for i, p in self.positions.items()]
|
|
123
124
|
self._writer.write_data("positions", data)
|
|
124
125
|
|
|
126
|
+
def dump_instrument(self, instrument: Instrument, timestamp: np.datetime64) -> None:
|
|
127
|
+
"""Write a single position snapshot row for ``instrument`` (used for on-fill event logging)."""
|
|
128
|
+
position = self.positions.get(instrument)
|
|
129
|
+
if position is None:
|
|
130
|
+
return
|
|
131
|
+
self._writer.write_data("positions", [self._position_row(instrument, position, timestamp)])
|
|
132
|
+
|
|
125
133
|
|
|
126
134
|
class PortfolioLogger(PositionsDumper):
|
|
127
135
|
"""
|
|
@@ -343,11 +351,12 @@ class StrategyLogging:
|
|
|
343
351
|
def __init__(
|
|
344
352
|
self,
|
|
345
353
|
logs_writer: LogsWriter | None = None,
|
|
346
|
-
positions_log_freq: str = "1Min",
|
|
347
|
-
portfolio_log_freq: str = "5Min",
|
|
354
|
+
positions_log_freq: str | None = "1Min",
|
|
355
|
+
portfolio_log_freq: str | None = "5Min",
|
|
348
356
|
num_exec_records_to_write=1, # in live let's write every execution
|
|
349
357
|
num_signals_records_to_write=1,
|
|
350
358
|
heartbeat_freq: str | None = None,
|
|
359
|
+
positions_log_on_change: bool = False,
|
|
351
360
|
) -> None:
|
|
352
361
|
# - instantiate loggers
|
|
353
362
|
if logs_writer:
|
|
@@ -367,13 +376,16 @@ class StrategyLogging:
|
|
|
367
376
|
if num_signals_records_to_write >= 1:
|
|
368
377
|
self.signals_logger = SignalsAndTargetsLogger(logs_writer, num_signals_records_to_write)
|
|
369
378
|
|
|
370
|
-
# - balance logger
|
|
371
|
-
|
|
379
|
+
# - balance logger (tracks positions_log_freq when set, otherwise portfolio_log_freq)
|
|
380
|
+
balance_freq = positions_log_freq or portfolio_log_freq
|
|
381
|
+
if balance_freq:
|
|
382
|
+
self.balance_logger = BalanceLogger(logs_writer, balance_freq)
|
|
372
383
|
else:
|
|
373
384
|
logger.warning("Log writer is not defined - strategy activity will not be saved !")
|
|
374
385
|
|
|
375
386
|
self.logs_writer = logs_writer
|
|
376
387
|
self.heartbeat_freq = convert_tf_str_td64(heartbeat_freq) if heartbeat_freq else None
|
|
388
|
+
self.positions_log_on_change = positions_log_on_change
|
|
377
389
|
|
|
378
390
|
def initialize(
|
|
379
391
|
self,
|
|
@@ -431,6 +443,10 @@ class StrategyLogging:
|
|
|
431
443
|
def save_deals(self, instrument: Instrument, deals: list[Deal]):
|
|
432
444
|
if self.executions_logger:
|
|
433
445
|
self.executions_logger.record_deals(instrument, deals)
|
|
446
|
+
if self.positions_log_on_change and self.positions_dumper and deals:
|
|
447
|
+
latest_deal_time = max(d.time for d in deals)
|
|
448
|
+
ts = latest_deal_time.as_unit("ns").asm8 if isinstance(latest_deal_time, pd.Timestamp) else latest_deal_time
|
|
449
|
+
self.positions_dumper.dump_instrument(instrument, ts)
|
|
434
450
|
|
|
435
451
|
def save_targets(self, targets: list[TargetPosition]):
|
|
436
452
|
if self.signals_logger and targets:
|
|
@@ -8,6 +8,12 @@ NS = 1_000_000_000
|
|
|
8
8
|
|
|
9
9
|
cpdef recognize_time(time):
|
|
10
10
|
if isinstance(time, str):
|
|
11
|
+
# Strip timezone suffix (e.g. 'Z', '+00:00') — np.datetime64 expects tz-naive ISO strings.
|
|
12
|
+
# All incoming timestamps are assumed UTC.
|
|
13
|
+
if time.endswith('Z') or time.endswith('z'):
|
|
14
|
+
time = time[:-1]
|
|
15
|
+
elif '+' in time[10:]:
|
|
16
|
+
time = time[:time.rindex('+')]
|
|
11
17
|
return np.datetime64(time, 'ns')
|
|
12
18
|
elif isinstance(time, np.datetime64):
|
|
13
19
|
return time
|
|
@@ -106,8 +106,9 @@ class WarmupConfig(StrictBaseModel):
|
|
|
106
106
|
|
|
107
107
|
class LoggingConfig(StrictBaseModel):
|
|
108
108
|
logger: str
|
|
109
|
-
position_interval: str
|
|
110
|
-
portfolio_interval: str
|
|
109
|
+
position_interval: str | None = None
|
|
110
|
+
portfolio_interval: str | None = None
|
|
111
|
+
position_log_on_change: bool = False
|
|
111
112
|
args: dict = Field(default_factory=dict)
|
|
112
113
|
heartbeat_interval: str | None = None
|
|
113
114
|
|
|
@@ -693,6 +693,7 @@ def _setup_strategy_logging(
|
|
|
693
693
|
positions_log_freq=log_config.position_interval,
|
|
694
694
|
portfolio_log_freq=log_config.portfolio_interval,
|
|
695
695
|
heartbeat_freq=log_config.heartbeat_interval,
|
|
696
|
+
positions_log_on_change=log_config.position_log_on_change,
|
|
696
697
|
)
|
|
697
698
|
return stg_logging
|
|
698
699
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/bitfinex/bitfinex_account.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/__init__.py
RENAMED
|
File without changes
|
{qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/account.py
RENAMED
|
File without changes
|
{qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/broker.py
RENAMED
|
File without changes
|
{qubx-1.2.2.dev2 → qubx-1.2.3.dev1}/src/qubx/connectors/ccxt/exchanges/hyperliquid/hyperliquid.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|