Skip to content

v7.8.4

Latest

Choose a tag to compare

@enarjord enarjord released this 06 Mar 16:28
· 25 commits to master since this release

Changed

  • Dual balance routing (raw vs hysteresis-snapped) - Live and orchestrator flows now carry both balance_raw (raw wallet balance) and balance (hysteresis-snapped balance). Sizing/order-shaping paths use snapped balance, while risk/accounting paths use raw balance (including realized-loss gate peak/floor checks, TWEL entry/auto-reduce gating, and auto-unstuck allowance calculations). This applies consistently across live and backtest via Rust orchestrator input.
  • WEL denominator behavior split by mode - Live now uses a hard fixed denominator for per-symbol WEL (total_wallet_exposure_limit / config.bot.{pside}.n_positions), removing runtime denominator drift from open-position count. Backtests now expose backtest.dynamic_wel_by_tradability (default true): when enabled, WEL uses tradability-aware denominator growth (min(n_positions, n_tradable_max)) based on coins with real candles, and does not shrink after delistings; when disabled, backtests use the same fixed denominator as live.
  • Bulk price fetch for Hyperliquid - calc_ideal_orders now uses a single allMids API call to get prices for all symbols instead of individual get_current_close calls per symbol (1 call vs ~70). Falls back to per-symbol fetches for non-Hyperliquid exchanges or on error.
  • Sequential margin mode setting for Hyperliquid - Margin mode and leverage API calls are now sequential with a small delay instead of being fired in parallel, reducing API burst on coin changes.

Fixed

  • Bybit fill-event qty inflation on duplicate pages - BybitFetcher now deduplicates fetch_my_trades rows by exec id before canonicalization/coalescing, preventing duplicate pagination rows from inflating canonical qty, fees, and close PnL.
  • Balance peak drift in wrong direction under hysteresis - Peak reconstruction (balance + (pnl_cumsum_max - pnl_cumsum_last)) previously used hysteresis-snapped balance in some paths. Since snapped balance can stay stale while pnl_cumsum_last changes fill-by-fill, this made reconstructed peak drift down after profits and up after losses. Peak/PnL-accuracy-sensitive paths now use raw balance (balance_raw) consistently.
  • Pytest Rust-module bootstrap fallback - Test bootstrap now tries the project venv passivbot_rust package before falling back to the lightweight stub when tests are launched outside the venv, reducing false failures from missing/incorrect Rust module resolution.
  • max_ohlcv_fetches_per_minute ignored when forager slots open - The rate limit config was only applied when all position slots were full. With open slots (the common case), all candidate symbols were fetched without rate limiting, causing 429 errors on Hyperliquid.
  • Hyperliquid positions+balance double fetch - fetch_positions and fetch_balance now share a single API call via a dedup lock instead of making two identical clearinghouseState requests per execution cycle.
  • Thundering herd on minute boundary - get_candles no longer force-refreshes all symbols simultaneously when a new minute boundary crosses. A 1-candle staleness tolerance prevents the TTL override that caused all symbols to fetch at once.
  • Candle refresh TTLs aligned to 1-minute finalization - Active candle refresh TTL raised from 10s to 60s and EMA close TTL from 30s to 60s, matching the actual 1-minute candle finalization interval.
  • Boot stagger for multi-bot setups - Added boot_stagger_seconds config (default 30s for Hyperliquid) to randomize startup delay, preventing simultaneous API bursts when multiple bots share the same IP.
  • Warmup and refresh fetch pacing - Added configurable warmup_fetch_delay_ms (default 200ms for Hyperliquid) with delays between individual symbol fetches during warmup, forager refresh, and active candle refresh loops.
  • Exponential backoff on 429 errors - WebSocket watch_orders uses exponential backoff (up to 30s) on rate limit errors. Execution loop backs off 5s on RateLimitExceeded. Hourly init_markets catches rate limits with 10s recovery.
  • Fill events pagination abort on repeated rate limits - HyperliquidFetcher now aborts after 5 consecutive rate limit retries with exponential backoff instead of retrying indefinitely.
  • EMA bundle and active candle sweep abort on rate limit - Both _load_orchestrator_ema_bundle and update_ohlcvs_1m_for_actives skip remaining symbols when the CandlestickManager's global rate limit backoff is active.
  • Live close-EMA failure handling in orchestrator feed - _load_orchestrator_ema_bundle() no longer silently drops failed/non-finite close EMA spans. It now fails loudly when no prior EMA exists, and otherwise reuses the last successfully computed close EMA for that exact symbol/span with explicit [ema] warning logs (including reason, age, and consecutive fallback count).
  • Required 1h log-range EMA handling in orchestrator feed - _load_orchestrator_ema_bundle() now fails loudly when required h1 log-range spans (from entry_volatility_ema_span_hours) are missing or non-finite, instead of deferring to downstream Rust MissingEma errors.
  • EMA bundle fetch stability under lock contention - Orchestrator EMA bundle loading now fetches per-symbol spans serially and drains all symbol task outcomes before re-raising, reducing same-symbol candle-lock contention and eliminating unretrieved sibling-task exception noise.

Added

  • Fill events doctor tool - Added src/tools/fill_events_doctor.py to audit cached fill events and auto-repair known Bybit duplicate-fill anomalies without requiring exchange API calls. Bybit startup now runs doctor by default (can be disabled with PASSIVBOT_FILL_EVENTS_DOCTOR=off).

Full changelog: v7.8.3...v7.8.4