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 <noreply@anthropic.com>
This commit is contained in:
@@ -674,10 +674,15 @@ async fn load_prior_summary(ledger: &Path, swym: &SwymClient) -> Option<String>
|
|||||||
// We use the full strategy JSON as the grouping key.
|
// We use the full strategy JSON as the grouping key.
|
||||||
let mut strategy_groups: std::collections::HashMap<String, Vec<(&LedgerEntry, Option<&RunMetricsSummary>)>> =
|
let mut strategy_groups: std::collections::HashMap<String, Vec<(&LedgerEntry, Option<&RunMetricsSummary>)>> =
|
||||||
std::collections::HashMap::new();
|
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 {
|
for entry in &entries {
|
||||||
let key = serde_json::to_string(&entry.strategy).unwrap_or_default();
|
let key = serde_json::to_string(&entry.strategy).unwrap_or_default();
|
||||||
|
let group = strategy_groups.entry(key).or_default();
|
||||||
|
if group.len() < 3 {
|
||||||
let m = metrics_map.get(&entry.run_id).copied();
|
let m = metrics_map.get(&entry.run_id).copied();
|
||||||
strategy_groups.entry(key).or_default().push((entry, m));
|
group.push((entry, m));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute avg sharpe per strategy group
|
// Compute avg sharpe per strategy group
|
||||||
|
|||||||
@@ -499,14 +499,22 @@ pub fn initial_prompt(instruments: &[String], candle_intervals: &[String], prior
|
|||||||
Some(s) => format!("{s}\n\n"),
|
Some(s) => format!("{s}\n\n"),
|
||||||
None => String::new(),
|
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!(
|
format!(
|
||||||
r#"{prior_section}Design a trading strategy for crypto spot markets.
|
r#"{prior_section}Design a trading strategy for crypto spot markets.
|
||||||
|
|
||||||
Available instruments: {}
|
Available instruments: {}
|
||||||
Available candle intervals: {}
|
Available candle intervals: {}
|
||||||
|
|
||||||
Start with a multi-timeframe trend-following approach with proper risk management
|
{starting_instruction} Use "usdc" as the quote asset.
|
||||||
(stop-loss, time exit, and ATR-based position sizing). Use "usdc" as the quote asset.
|
|
||||||
|
|
||||||
Respond with ONLY the strategy JSON."#,
|
Respond with ONLY the strategy JSON."#,
|
||||||
instruments.join(", "),
|
instruments.join(", "),
|
||||||
|
|||||||
Reference in New Issue
Block a user