From b476199de854bc481f1ecff3f300a9d6b3eb7881 Mon Sep 17 00:00:00 2001 From: rob thijssen Date: Tue, 10 Mar 2026 13:54:35 +0200 Subject: [PATCH] Fix ledger context being overridden by prescriptive initial prompt The 13:20:03 run showed the ledger context was counterproductive: the initial prompt's "Start with a multi-timeframe trend-following approach" instruction caused the model to ignore the prior summary and repeat EMA50-based strategies that produced 0 trades across all 15 iterations. Two fixes: - When prior_summary is present, replace the prescriptive starting instruction with one that explicitly defers to the ledger: refine the best prior strategy or try a different approach if all prior results were poor. Prevents the fixed instruction from overriding the context. - Cap ledger entries per unique strategy at 3. A strategy repeated across 11 iterations would contribute 33 entries, drowning out other approaches in the prior summary. 3 entries (one per instrument) is sufficient. Co-Authored-By: Claude Sonnet 4.6 --- src/agent.rs | 9 +++++++-- src/prompts.rs | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 7d37ca7..4a62587 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -674,10 +674,15 @@ async fn load_prior_summary(ledger: &Path, swym: &SwymClient) -> Option // We use the full strategy JSON as the grouping key. let mut strategy_groups: std::collections::HashMap)>> = std::collections::HashMap::new(); + // Cap at 3 entries per unique strategy (one per instrument is enough). + // Without this, a strategy repeated across many iterations swamps the summary. for entry in &entries { let key = serde_json::to_string(&entry.strategy).unwrap_or_default(); - let m = metrics_map.get(&entry.run_id).copied(); - strategy_groups.entry(key).or_default().push((entry, m)); + let group = strategy_groups.entry(key).or_default(); + if group.len() < 3 { + let m = metrics_map.get(&entry.run_id).copied(); + group.push((entry, m)); + } } // Compute avg sharpe per strategy group diff --git a/src/prompts.rs b/src/prompts.rs index a9f9147..680ca87 100644 --- a/src/prompts.rs +++ b/src/prompts.rs @@ -499,14 +499,22 @@ pub fn initial_prompt(instruments: &[String], candle_intervals: &[String], prior Some(s) => format!("{s}\n\n"), None => String::new(), }; + let starting_instruction = if prior_summary.is_some() { + "Based on the prior results above: if the best strategy has promising metrics, \ +refine it. If all prior results were poor (0 trades or deeply negative Sharpe), try a \ +clearly different indicator family or candle interval than what was already attempted. \ +Do NOT repeat approaches that consistently produced 0 trades." + } else { + "Start with a multi-timeframe trend-following approach with proper risk management \ +(stop-loss, time exit, and ATR-based position sizing)." + }; format!( r#"{prior_section}Design a trading strategy for crypto spot markets. Available instruments: {} Available candle intervals: {} -Start with a multi-timeframe trend-following approach with proper risk management -(stop-loss, time exit, and ATR-based position sizing). Use "usdc" as the quote asset. +{starting_instruction} Use "usdc" as the quote asset. Respond with ONLY the strategy JSON."#, instruments.join(", "),