agentleFS
QuantConnectQuantConnect/Documentation/skills/csharp/debug-performance/SKILL.md

debug-performance

Skill268 starsChanged 48 days agoApache-2.0View on GitHub

Diagnoses slow QuantConnect Python (.py) and C# (.cs) backtests using the Performance Chart first and Python cProfile only when the chart does not pinpoint the hot function. Trigger phrases: "slow backtest", "high CPU", "algorithm slow", "CPU usage", "RAM usage", "memory usage", "performance chart", "profiling", "bottleneck", "debug performance", "taking too long", "optimize algorithm".

2 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 7 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈7

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Never introduce pytry/exceptcstry/catch or pyhasattr/getattr/setattr/isinstancecsreflection.

    line 15
  2. Distinctive:

    Read which series dominates:

    line 32
  3. Distinctive:

    If multiple series spike together, start with the earliest causal source: Subscriptions before Consolidators, Consolidators before OnData, …

    line 39
  4. Distinctive:

    Remove diagnostic logs after the fix.

    line 68
  5. Distinctive:

    Use cProfile only when CPU, ManagedRAM, or TotalRAM is high and the Performance Chart does not isolate the expensive function.

    line 71
  6. Distinctive:

    Read the cumulative time column in the backtest logs.

    line 78
  7. Distinctive:

    Remove the profiler after measurement unless the user explicitly wants another profiling run.

    line 80
  8. Distinctive:

    No banned error-hiding pattern (Section 0).

    line 84

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

/debug-performance - QuantConnect Performance Debugging

Invoked on a slow backtest. Work top to bottom. Find the dominant cost before changing code. Same Performance Chart rules for main.py and main.cs; Python can add cProfile only when Section 4 says to.

0. Never add error-hiding patterns

Never introduce pytry/exceptcstry/catch or pyhasattr/getattr/setattr/isinstancecsreflection. They hide the exact failure or slow path. A profiler wrapper measures work; it is not a catch. If existing code wraps the slow region in one, remove it, re-run, read the real behavior, then continue.

1. Enable Performance Chart first

Record the original pyset_start_date/set_end_datecsSetStartDate/SetEndDate and universe, then shrink both: usually 1 to 3 months and the smallest universe that still reproduces the slowdown. Set Settings.PerformanceSamplePeriod = TimeSpan.FromDays(7) in Initialize, then run the short backtest. Open the results and inspect the Performance Chart. Record the dominant series: the tallest spike, or the sustained plateau if there is no single spike. Do not optimize before naming the series.

2. Route by dominant series

Read which series dominates:

  • Selection, Consolidators, OnData, Schedule, Subscriptions, Securities, Transactions, SplitsDividendsDelisting, Slice, HistoryDataPoints, or ActiveSecurities -> Section 3.
  • CPU, ManagedRAM, or TotalRAM high with no single time-series dominant -> Section 4 for Python, or keep using the chart for C#.
  • DataPoints low -> Section 3, Subscriptions row. If multiple series spike together, start with the earliest causal source: Subscriptions before Consolidators, Consolidators before OnData, Selection before Securities or Transactions. Treat CPU and RAM as symptoms until the chart or profiler names the code path.

3. Fix by bottleneck

Change only the code path that corresponds to the dominant series. Re-run the same short backtest after each change and compare the same chart region. For rolling calculations, use this order: built-in indicator first, indicator extension second, Security.session for cached OHLCV/session data third, and manual RollingWindow/deque only when LEAN has no built-in equivalent. Example: a trailing mean of closes is an SMA, so use pyself.sma(security, period) instead of storing closes and averaging them manually.

SeriesMeaningFix
SelectionUniverse add/remove and selection functions.Reduce coarse universe size; move expensive fundamental queries out of the filter; cache results across calls.
ConsolidatorsConsolidation, indicator updates, consolidator handlers.Reduce universe size; consolidate at a coarser resolution; share one consolidator where logic allows.
OnDataOnData and alpha update time.Move heavy logic to a scheduled event; replace manual series calculations with a built-in indicator or indicator extension before considering a manual window.
ScheduleScheduled event handler time.Reduce event frequency; cache intermediate results computed in the handler.
SubscriptionsTime reading subscribed data.Reduce data resolution or universe size; confirm only needed resolutions are subscribed.
SecuritiesSecurity updates, security changes, symbol changes.Reduce ActiveSecurities count, usually fewer holdings or open orders.
TransactionsOrder event processing.Batch orders via portfolio targets; reduce rebalance frequency.
SplitsDividendsDelistingCorporate action events.Reduce universe size or move corporate-action logic out of the handler.
SliceTime creating the Slice object.Reduce subscription count, resolution, and custom data fields before optimizing handlers.
HistoryDataPointsHistory provider data points.Reduce History calls; replace rolling calculations with indicators/extensions; use Security.Session for cached OHLCV/session data; request fewer symbols, fields, or bars.
ActiveSecuritiesSelected securities plus holdings and open orders.Prune stale symbols; liquidate or cancel old positions/orders before broadening the universe.
Logging rules: measure with Log(...) in the narrow handler
being debugged. Never use the Object Store for profiler output. Never log inside
OnData or an often-firing scheduled event without a counter limit.
Remove diagnostic logs after the fix.

4. Python profiler with logs

Use cProfile only when CPU, ManagedRAM, or TotalRAM is high and the Performance Chart does not isolate the expensive function. This is Python only. C# does not have a built-in cProfile equivalent; use the chart series exclusively.

  1. At the top of main.py, before the class:
  2. In OnEndOfAlgorithm, disable the profiler and log the top cumulative-time lines. Do not save the report to the Object Store:
  3. Read the cumulative time column in the backtest logs. The top function is the bottleneck; map it back to a Section 3 series and apply the matching fix. Remove the profiler after measurement unless the user explicitly wants another profiling run.

5. Checklist

  1. No banned error-hiding pattern (Section 0).
  2. Original dates + universe recorded before shrinking.
  3. Performance Chart enabled; short backtest run to expose the dominant series.
  4. Dominant series identified before applying any fix (Section 2).
  5. Fix targets the real bottleneck series, not a guess (Section 3).
  6. Built-in indicators/extensions considered before adding pyRollingWindow/dequecsRollingWindow.
  7. Profiler used only for Python when chart alone does not pinpoint the function.
  8. Profiler output logged with Log; Object Store not used.
  9. Original period + universe restored; final backtest confirms the spike is gone.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.