Skip to content

Add big-request guardrails and honest resource diagnostics - #9669

Open
jhonabreul wants to merge 11 commits into
QuantConnect:masterfrom
jhonabreul:feature-big-request-guardrails
Open

Add big-request guardrails and honest resource diagnostics#9669
jhonabreul wants to merge 11 commits into
QuantConnect:masterfrom
jhonabreul:feature-big-request-guardrails

Conversation

@jhonabreul

@jhonabreul jhonabreul commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds four independent warn-don't-fail diagnostics for big-request failure modes that today surface as opaque or misleading fatal errors. Runs that would have succeeded are unaffected; all thresholds are config overridable, and the diagnostics never throw: a failure while checking or emitting a warning is logged and disables the check instead of interfering with the algorithm.

  • Honest OOM diagnostic in ZipDataCacheProvider.Fetch: allocation failures wrapped by Ionic were logged as Corrupt zip file/entry and swallowed. An OutOfMemoryException anywhere in the chain is now rethrown as a memory diagnostic. Truly corrupt zips keep the old behavior.
  • Large history request warning (in the QCAlgorithm.History funnel, so all overloads): warns once over an estimated data-cell threshold (default 5M), and warns once when 30 consecutive large calls have overlapping time windows (the re-fetch-a-long-lookback-every-day pattern). Tick history is estimated at 10 data points per second of market time, grounded on the repo's SPY sample data (~10.7 trade and ~115 quote ticks per second).
  • Early slow time step warning: AlgorithmTimeLimitManager logs a warning once per time step over a threshold (default 3 minutes) instead of staying silent until the isolator kill, and TimeMonitor now names the running scheduled event when it crosses the one-minute mark. Both warnings also reach the user's log file through the result handler's debug messages, not just the engine log.
  • Large universe selection warning: warns once when universe selections grow past a per-resolution symbol threshold table (universe-selection-size-warning-thresholds, a JSON object with defaults Tick 100, Second 250, Minute 500, Hour 1000, Daily 2000; a resolution set to a non positive value is disabled). All universe types are covered and consume a single shared budget: each universe contributes its selection size divided by its resolution's threshold, warning when the combined load reaches one, so many small selections across resolutions accumulate like a single wide one. Option chain universes get the narrow-the-filter suggestion (SetFilter/AddOptionContract); other universes are pointed at selecting fewer symbols or a coarser universe resolution.

Related Issue

N/A

Motivation and Context

These failure modes cost hours: a wide option universe dying as "corrupt zip" (actually OOM), billion-cell history re-fetches stalling backtests, and 10-minute isolator kills that never name the slow handler. Upfront, named warnings make them self-correcting.

Requires Documentation Change

No. The new config keys only tune warnings and have safe defaults.

How Has This Been Tested?

  • New unit tests per diagnostic, each proven red on pre-change code: OOM rethrow + corrupt-zip regression guard, history size/overlap/tick warnings, time-step warning (once per step, re-arms on new step, also reaches the user handler), named scheduled event log (engine and user channels), universe selection warning (under/over threshold, resolution aware, cross-resolution aggregation, once per algorithm).
  • Touched fixtures all green: zip cache, time-limit manager, isolator, universe selection, real-time handler, plus the full AlgorithmHistoryTests fixture.
  • BasicTemplateOptionsAlgorithm (C# + Python) statistics unchanged.
  • End-to-end Launcher runs verified each warning fires with the expected text and the runs complete normally.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking change which improves implementation)
  • Performance (non-breaking change which improves performance. Please add associated performance test and results)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Non-functional change (xml comments/documentation/etc)

Checklist:

  • My code follows the code style of this project.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My branch follows the naming convention bug-<issue#>-<description> or feature-<issue#>-<description>

Moves the large/overlapping history request warning state and logic out
of the QCAlgorithm partial into a private LargeHistoryRequestDiagnostics
nested class with a single entry point, keeping the algorithm class
surface small. No behavior change.
Keep the new user-facing warnings and code comments short and direct so
they are easy to act on. No behavior change.
@jhonabreul
jhonabreul marked this pull request as ready for review August 12, 2026 17:57
Estimate tick history at 10 data points per second: one per second
underestimates liquid symbols by 1-2 orders of magnitude (SPY 2013-10-07
sample data: ~10.7 trade and ~115 quote ticks per second), letting
OOM-prone tick history requests slip under the warning threshold.

Never throw from the diagnostics checks: failures while checking
requests or emitting warnings are logged and disable the checks instead
of interfering with the algorithm.
Replace the option-only contract count warning with a check covering
every universe. Because the cost of a selected symbol grows with the
resolution its subscriptions are added at, the flat contract threshold
becomes a per-resolution table ('universe-selection-size-warning-
thresholds', a JSON object like {"Minute": 500}). All universes consume
a single shared budget: each universe contributes selection size over
its resolution's threshold, warning when the combined load reaches one,
so many small selections across resolutions accumulate like a single
wide one. The warning never throws: failures are logged and disable the
check instead of interfering with the algorithm.
One minute is close enough to normal heavy steps (warm up, coarse
selection days) to be noisy; three minutes keeps the warning early
relative to the twenty minute kill while only firing on genuinely
abnormal steps.
The slow time step and long-running scheduled event warnings only went
to the engine log, which does not reach the user's log file. Both now
also route through the result handler's debug messages via an optional
user warning handler, wired in AlgorithmManager.Run and
BaseRealTimeHandler.Setup. Only the first scheduled event minute
crossing is surfaced to the user; later crossings stay engine-side to
avoid flooding user logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant