From 24dc96477dbecec9f9b1018416d6efbdc63af82d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 15:37:42 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Optimize=20backtest=20candi?= =?UTF-8?q?date=20deduplication=20loop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 What: Replaced a heavy chain of `.map()`, array spreading, `new Set()`, `Array.from()`, and `.slice()` with bounded `for` loops in the backtest runner. 🎯 Why: High-frequency backtesting engines suffer when allocating large intermediate arrays inside hot loops, creating significant garbage collection (GC) overhead. 📊 Impact: Eliminates three intermediate array allocations and truncates iteration early if the max candidate count is reached, saving memory overhead in each step of the backtest loop. 🔬 Measurement: Verify via backtest run performance and `pnpm test`. Co-authored-by: toreleon <42534763+toreleon@users.noreply.github.com> --- .jules/bolt.md | 1 + src/agent/backtestRunner.ts | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 289fae6..1d240fb 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -23,3 +23,4 @@ ## 2026-09-19 - Avoid chained array methods before Set initialization **Learning:** Chaining `.map().filter()` inside a `new Set()` constructor creates multiple intermediate arrays, causing unnecessary memory allocation and garbage collection overhead in hot paths (like ticker normalization during discovery). **Action:** Replace chained array methods with a direct indexed `for` loop that transforms, validates, and `.add()`s directly to a freshly initialized `Set`. +## 2025-09-29 - [Avoid chained array allocations in backtests]\n**Learning:** High-frequency backtests suffer when allocating intermediate arrays in hot loops (e.g., using chained `.map()`, array spreads, and `.slice()`). These create significant GC overhead.\n**Action:** Replace functional array pipelines with bounded `for` loops and `Set`s with early-exit conditions when extracting deduplicated bounded subsets. diff --git a/src/agent/backtestRunner.ts b/src/agent/backtestRunner.ts index e53b03c..34e222b 100644 --- a/src/agent/backtestRunner.ts +++ b/src/agent/backtestRunner.ts @@ -347,10 +347,18 @@ export async function runBacktestSession( universe: BACKTEST_DISCOVERY_UNIVERSE, limit: maxCandidates, }); - const held = (await broker.snapshot()).positions.map((p) => p.ticker); - const tickers = Array.from( - new Set([...held, ...discovery.candidates.map((c) => c.ticker)]), - ).slice(0, maxCandidates); + const snap = await broker.snapshot(); + // ⚡ Bolt: Removed .map(), spread, and .slice() chain to avoid allocating large intermediate arrays in backtests + const tickersSet = new Set(); + const positions = snap.positions; + for (let i = 0; i < positions.length && tickersSet.size < maxCandidates; i++) { + tickersSet.add(positions[i]!.ticker); + } + const candidates = discovery.candidates; + for (let i = 0; i < candidates.length && tickersSet.size < maxCandidates; i++) { + tickersSet.add(candidates[i]!.ticker); + } + const tickers = Array.from(tickersSet); const decisions: FinalDecision[] = []; for (const ticker of tickers) {