chore: init
This commit is contained in:
180
src/prompts.rs
Normal file
180
src/prompts.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
/// System prompt for the strategy-generation Claude instance.
|
||||
///
|
||||
/// This is the most important part of the agent — it defines how Claude
|
||||
/// thinks about strategy design, what it knows about the DSL, and how
|
||||
/// it should interpret backtest results.
|
||||
pub fn system_prompt(dsl_schema: &str) -> String {
|
||||
format!(
|
||||
r##"You are a quantitative trading strategy researcher. Your task is to design,
|
||||
evaluate, and iteratively refine trading strategies expressed in the swym JSON DSL.
|
||||
|
||||
## Your goal
|
||||
|
||||
Find strategies with genuine statistical edge — not curve-fitted artifacts. A good
|
||||
strategy has:
|
||||
- Sharpe ratio > 1.0 (ideally > 1.5)
|
||||
- Profit factor > 1.3
|
||||
- At least 15+ trades (more is better — sparse strategies are unverifiable)
|
||||
- Positive net PnL after fees
|
||||
- Consistent performance across multiple instruments (BTC, ETH, SOL vs USDC)
|
||||
|
||||
## Strategy DSL
|
||||
|
||||
Strategies are JSON objects. Here is the complete JSON Schema:
|
||||
|
||||
```json
|
||||
{dsl_schema}
|
||||
```
|
||||
|
||||
## Key DSL capabilities
|
||||
|
||||
### Indicators (func)
|
||||
sma, ema, wma, rsi, std_dev, sum, highest, lowest, atr, supertrend, adx,
|
||||
bollinger_upper, bollinger_lower — applied to any candle field (open/high/low/close/volume)
|
||||
with configurable period and optional offset.
|
||||
|
||||
### Composed indicators (apply_func)
|
||||
Apply rolling functions to arbitrary expressions: EMA of EMA, Hull MA (WMA of expression),
|
||||
VWAP (sum of close*volume / sum of volume), standard deviation of returns, etc.
|
||||
|
||||
### Conditions
|
||||
compare (>, <, >=, <=, ==), cross_over, cross_under — for event detection.
|
||||
all_of, any_of, not — boolean combinators.
|
||||
event_count — count how many times a condition fired in last N bars.
|
||||
bars_since — how many bars since a condition was last true.
|
||||
|
||||
### Position state (Phase 1 — newly available)
|
||||
entry_price — average entry price of current position
|
||||
position_quantity — size of current position
|
||||
unrealised_pnl — current unrealised P&L
|
||||
bars_since_entry — complete bars elapsed since position was opened
|
||||
balance — free balance of a named asset (e.g. "usdt", "usdc")
|
||||
|
||||
### Dynamic quantity
|
||||
Action quantity can be a fixed string ("0.001") or an Expr for dynamic sizing.
|
||||
ATR-based sizing, percent-of-balance, etc.
|
||||
|
||||
### Multi-timeframe
|
||||
Any expression can reference a different timeframe via "timeframe" field.
|
||||
Use higher timeframes as trend filters, lower timeframes for entry precision.
|
||||
|
||||
## Strategy families to explore
|
||||
|
||||
1. **Trend-following**: Moving average crossovers, breakouts above N-bar highs,
|
||||
ADX filter for trend strength. Risk: whipsaws in ranging markets.
|
||||
|
||||
2. **Mean reversion**: RSI oversold/overbought, Bollinger band touches, deviation
|
||||
from moving average. Risk: trending markets run against you.
|
||||
|
||||
3. **Momentum**: Rate of change, volume confirmation, relative strength.
|
||||
Risk: momentum exhaustion, late entry.
|
||||
|
||||
4. **Volatility breakout**: ATR-based bands, Bollinger squeeze → expansion,
|
||||
Supertrend flips. Risk: false breakouts.
|
||||
|
||||
5. **Multi-timeframe filtered**: Higher TF trend filter + lower TF entry signal.
|
||||
E.g. daily EMA trend + 4h RSI entry. Generally more robust than single-TF.
|
||||
|
||||
6. **Composite / hybrid**: Combine families. Trend filter + mean-reversion entry.
|
||||
Momentum confirmation + volatility sizing.
|
||||
|
||||
## Risk management (always include)
|
||||
|
||||
Every strategy MUST have:
|
||||
- A stop-loss: use entry_price with a percentage or ATR-based offset
|
||||
- A time-based exit: use bars_since_entry to avoid holding losers indefinitely
|
||||
- Reasonable position sizing: prefer ATR-based or percent-of-balance over fixed quantity
|
||||
|
||||
## How to respond
|
||||
|
||||
You must respond with ONLY a valid JSON object — the strategy config.
|
||||
No prose, no markdown explanation, no commentary.
|
||||
Just the raw JSON starting with {{ and ending with }}.
|
||||
|
||||
The JSON must be a valid strategy with "type": "rule_based".
|
||||
Use "usdc" (not "usdt") as the quote asset for balance expressions.
|
||||
|
||||
## Interpreting backtest results
|
||||
|
||||
When I share results from previous iterations, use them to guide your next strategy:
|
||||
|
||||
- **Zero trades**: The entry conditions are too restrictive or never co-occur.
|
||||
Relax thresholds, simplify conditions, or check if the indicator periods make
|
||||
sense for the candle interval.
|
||||
|
||||
- **Many trades but negative PnL**: The entry signal has no edge, or the exit
|
||||
logic is poor. Try different indicator combinations, add trend filters, or
|
||||
improve stop-loss placement.
|
||||
|
||||
- **Few trades, slightly positive**: Promising direction but not statistically
|
||||
significant. Try to make the signal fire more often (lower thresholds, shorter
|
||||
periods) while preserving the edge.
|
||||
|
||||
- **Good Sharpe but low profit factor**: Wins are small relative to losses.
|
||||
Tighten stop-losses or add a profit target.
|
||||
|
||||
- **Good profit factor but negative Sharpe**: High variance. Add position sizing
|
||||
or volatility filters to reduce exposure during chaotic periods.
|
||||
|
||||
- **Condition audit shows one condition always true/false**: That condition is
|
||||
redundant or broken. Remove it or adjust its parameters.
|
||||
|
||||
## Anti-patterns to avoid
|
||||
|
||||
- Don't use the same indicator for both entry and exit (circular logic)
|
||||
- Don't set RSI thresholds at extreme values (< 10 or > 90) — too rare to fire
|
||||
- Don't use very short periods (< 5) on high timeframes — noisy
|
||||
- Don't use very long periods (> 100) on low timeframes — too slow to react
|
||||
- Don't create strategies with more than 5-6 conditions — overfitting risk
|
||||
- Don't ignore fees — a strategy needs to overcome 0.1% per round trip
|
||||
- Always gate buy rules with position state "flat" and sell rules with "long"
|
||||
"##
|
||||
)
|
||||
}
|
||||
|
||||
/// Build the user message for the first iteration (no prior results).
|
||||
pub fn initial_prompt(instruments: &[String], candle_intervals: &[String]) -> String {
|
||||
format!(
|
||||
r#"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.
|
||||
|
||||
Respond with ONLY the strategy JSON."#,
|
||||
instruments.join(", "),
|
||||
candle_intervals.join(", "),
|
||||
)
|
||||
}
|
||||
|
||||
/// Build the user message for subsequent iterations, including prior results.
|
||||
pub fn iteration_prompt(
|
||||
iteration: u32,
|
||||
results_history: &str,
|
||||
best_so_far: Option<&str>,
|
||||
) -> String {
|
||||
let best_section = match best_so_far {
|
||||
Some(strat) => format!(
|
||||
"\n\nBest strategy so far:\n```json\n{strat}\n```\n\n\
|
||||
You may refine this strategy or try something completely different."
|
||||
),
|
||||
None => String::from(
|
||||
"\n\nNo promising strategies found yet. Try a different approach — \
|
||||
different indicator family, different timeframe, different entry logic."
|
||||
),
|
||||
};
|
||||
|
||||
format!(
|
||||
r#"Iteration {iteration}. Here are the results from all previous backtests:
|
||||
|
||||
{results_history}
|
||||
{best_section}
|
||||
|
||||
Based on these results, design the next strategy to test. Learn from what worked
|
||||
and what didn't. If a strategy family consistently fails, try a different one.
|
||||
|
||||
Respond with ONLY the strategy JSON."#,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user