//! Common strategy seeds — seeded in every environment.

use super::StrategySeed;
use serde_json::json;

pub fn strategies() -> Vec<StrategySeed> {
    vec![
        hodl(),
        simple_trend(),
        simple_trend_v2(),
        buy_2_factors_reversion(),
        buy_2_factors_reversion_v2(),
        ichimoku(),
        ichimoku_v2(),
        bull_market_support_band(),
        bull_market_support_band_v2(),
        momentum_cascade(),
        gaussian_channel(),
        gaussian_channel_v3(),
        supertrend(),
        supertrend_v3(),
        money_line(),
        trend_detector(),
        stochastic_keltner(),
        stochastic_keltner_v3(),
        hull_suite(),
        supertrend_fusion(),
        emmanuel_ma(),
        emmanuel_ma_v2(),
        emmanuel_ma_v3(),
        emmanuel_ma_v4(),
        emmanuel_ma_v5(),
        emmanuel_ma_v6(),
        emmanuel_ma_v7(),
        emmanuel_ma_v8(),
        emmanuel_mtf_v1(),
        emmanuel_mtf_v2(),
        emmanuel_mtf_v3(),
        emmanuel_mtf_v4(),
    ]
}

// ---------------------------------------------------------------------------
// Implementable strategies (real rules)
// ---------------------------------------------------------------------------

fn hodl() -> StrategySeed {
    StrategySeed {
        name: "hodl",
        version: 1,
        description: "\
## HODL — Buy & Hold Benchmark

A simple buy-and-hold strategy that enters a position at the start and never exits.
Used as a benchmark: any active strategy should outperform this on a risk-adjusted basis.

**Entry**: Buy immediately (when flat).
**Exit**: Never.

This strategy is fully implemented.",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1d",
            "rules": [
                {
                    "comment": "Buy and hold: enter immediately when flat, never exit",
                    "when": { "kind": "position", "state": "flat" },
                    "then": { "side": "buy", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn simple_trend() -> StrategySeed {
    StrategySeed {
        name: "simple trend + regime filter",
        version: 1,
        description: "\
## Simple Trend + Regime Filter

A baseline trend-following strategy using an EMA crossover for signal generation.

**Concept**: Enter long when the fast EMA (20) crosses above the slow EMA (50), indicating
an uptrend. Exit when the fast EMA crosses back below the slow EMA.

**Full concept (partially implemented)**:
- Trend signal: EMA(20) crosses EMA(50)
- Regime filter: classify market as trending or ranging using ADX (>25 = trending) or
  choppiness index — only take trend signals when regime = trending

**Limitations**: Choppiness index is not in the DSL.
ADX is now available — the full regime filter could be added here if desired.
The regime filter is omitted; the strategy trades all crossovers regardless of regime.",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Enter long: fast EMA crosses above slow EMA",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            {
                                "kind": "cross_over",
                                "left":  { "kind": "func", "name": "ema", "field": "close", "period": 20 },
                                "right": { "kind": "func", "name": "ema", "field": "close", "period": 50 }
                            }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit long: fast EMA crosses below slow EMA",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            {
                                "kind": "cross_under",
                                "left":  { "kind": "func", "name": "ema", "field": "close", "period": 20 },
                                "right": { "kind": "func", "name": "ema", "field": "close", "period": 50 }
                            }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn buy_2_factors_reversion() -> StrategySeed {
    // Helper expressions reused across rules
    let rsi14 = json!({ "kind": "func", "name": "rsi", "field": "close", "period": 14 });
    let sma200 = json!({ "kind": "func", "name": "sma", "field": "close", "period": 200 });
    let close = json!({ "kind": "field", "field": "close" });

    StrategySeed {
        name: "buy 2 factors, reversion entry",
        version: 1,
        description: "\
## Buy 2 Factors, Reversion Entry

A mean-reversion approach filtered by two confirming factors.

**Full concept**:
Build a mean-reversion entry (price touches lower Bollinger Band or RSI < 30) gated by
two confirming factors:
1. Price above 200-period SMA (macro uptrend filter)
2. ADX > 20 (trend strength confirms non-ranging environment) OR positive MACD histogram

Enter on reversion signal; exit on mean return or trailing stop.

**Implemented (2 of 3 factors)**:
- Factor 1: price > SMA(200) ✓
- Factor 2: ADX not yet available in DSL — omitted
- Entry signal: RSI(14) < 30 ✓
- Exit: RSI(14) > 70 ✓

**Limitations**: ADX is now available in the DSL; MACD histogram requires DSL extensions.",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Enter long: RSI oversold + price above 200 SMA",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            {
                                "kind": "compare",
                                "left": rsi14.clone(),
                                "op": "<",
                                "right": { "kind": "literal", "value": "30" }
                            },
                            {
                                "kind": "compare",
                                "left": close.clone(),
                                "op": ">",
                                "right": sma200.clone()
                            }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit long: RSI overbought",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            {
                                "kind": "compare",
                                "left": rsi14,
                                "op": ">",
                                "right": { "kind": "literal", "value": "70" }
                            }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn ichimoku() -> StrategySeed {
    // Tenkan-sen = (highest(high, 9) + lowest(low, 9)) / 2
    let tenkan = json!({
        "kind": "bin_op", "op": "div",
        "left": {
            "kind": "bin_op", "op": "add",
            "left":  { "kind": "func", "name": "highest", "field": "high", "period": 9 },
            "right": { "kind": "func", "name": "lowest",  "field": "low",  "period": 9 }
        },
        "right": { "kind": "literal", "value": "2" }
    });

    // Kijun-sen = (highest(high, 26) + lowest(low, 26)) / 2
    let kijun = json!({
        "kind": "bin_op", "op": "div",
        "left": {
            "kind": "bin_op", "op": "add",
            "left":  { "kind": "func", "name": "highest", "field": "high", "period": 26 },
            "right": { "kind": "func", "name": "lowest",  "field": "low",  "period": 26 }
        },
        "right": { "kind": "literal", "value": "2" }
    });

    StrategySeed {
        name: "ichimoku",
        version: 1,
        description: "\
## Ichimoku Kinko Hyo

A well-known Japanese charting system providing support/resistance, trend direction,
and momentum signals from a single chart overlay.

**Components**:
- **Tenkan-sen** (Conversion): `(9-period high + 9-period low) / 2`
- **Kijun-sen** (Base): `(26-period high + 26-period low) / 2`
- **Senkou Span A** (Leading Span A): `(Tenkan + Kijun) / 2`, plotted 26 periods ahead
- **Senkou Span B** (Leading Span B): `(52-period high + 52-period low) / 2`, plotted 26 periods ahead
- **Chikou Span** (Lagging): Close plotted 26 periods back

**Classic entry (full)**:
Price above cloud, Tenkan crosses above Kijun, Chikou above price, future cloud is green (Span A > Span B).

**Implemented (core signal)**:
- Entry: Tenkan crosses above Kijun AND close > Kijun ✓
- Exit: Tenkan crosses below Kijun ✓
- Tenkan and Kijun are computed via `(highest + lowest) / 2` arithmetic ✓

**Limitations**: Senkou Span A/B require forward-projection (26 bars ahead) which is
not supported. Chikou Span cross-check is omitted. Cloud validation is omitted.",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Enter long: Tenkan crosses above Kijun and price above Kijun",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "cross_over", "left": tenkan.clone(), "right": kijun.clone() },
                            {
                                "kind": "compare",
                                "left": { "kind": "field", "field": "close" },
                                "op": ">",
                                "right": kijun.clone()
                            }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit long: Tenkan crosses below Kijun",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            { "kind": "cross_under", "left": tenkan, "right": kijun }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn bull_market_support_band() -> StrategySeed {
    // The "band" is the zone between SMA(100) and EMA(105) on the daily chart
    // (approximating the weekly 20 SMA and 21 EMA).
    let sma100 = json!({ "kind": "func", "name": "sma", "field": "close", "period": 100 });
    let ema105 = json!({ "kind": "func", "name": "ema", "field": "close", "period": 105 });
    let sma100_prev = json!({ "kind": "func", "name": "sma", "field": "close", "period": 100, "offset": 1 });
    let ema105_prev = json!({ "kind": "func", "name": "ema", "field": "close", "period": 105, "offset": 1 });
    let close = json!({ "kind": "field", "field": "close" });
    let close_prev = json!({ "kind": "field", "field": "close", "offset": 1 });

    StrategySeed {
        name: "bull market support band",
        version: 1,
        description: "\
## Bull Market Support Band

A well-known concept from crypto and equity analysis, popularised by Benjamin Cowen.

**Concept**:
- Calculate the 20-week SMA and 21-week EMA. On daily charts that is approximately
  SMA(100) and EMA(105).
- The zone between them forms the \"support band\".
- Long entry: price pulls back to the band and bounces (close above both MAs after touching).
- Exit: price closes below both MAs.
- Only active in confirmed bull markets (price has been above band for an extended period).

**Implemented**:
- Entry: price[1] was below SMA(100)[1] (touched/entered band) and close > SMA(100) and close > EMA(105) (bounced) ✓
- Exit: close < SMA(100) and close < EMA(105) ✓
- Uses SMA(100) + EMA(105) as the daily proxies for weekly MAs ✓

**Limitations**: No explicit bull market confirmation filter (extended-period price check
requires bar counting which is not in the DSL).",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1d",
            "rules": [
                {
                    "comment": "Enter long: price bounces off support band (was below, now above both MAs)",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            {
                                "kind": "compare",
                                "left": close_prev.clone(),
                                "op": "<",
                                "right": sma100_prev.clone()
                            },
                            {
                                "kind": "compare",
                                "left": close.clone(),
                                "op": ">",
                                "right": sma100.clone()
                            },
                            {
                                "kind": "compare",
                                "left": close.clone(),
                                "op": ">",
                                "right": ema105.clone()
                            }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit long: price closes below both band MAs",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            {
                                "kind": "compare",
                                "left": close.clone(),
                                "op": "<",
                                "right": sma100.clone()
                            },
                            {
                                "kind": "compare",
                                "left": close.clone(),
                                "op": "<",
                                "right": ema105_prev
                            }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn momentum_cascade() -> StrategySeed {
    // EMA(20) crossover as short-term entry trigger, EMA(50)/EMA(200) for trend filter,
    // ADX(14) > 25 for momentum confirmation.
    let ema20 = json!({ "kind": "func", "name": "ema", "field": "close", "period": 20 });
    let ema50 = json!({ "kind": "func", "name": "ema", "field": "close", "period": 50 });
    let ema200 = json!({ "kind": "func", "name": "ema", "field": "close", "period": 200 });
    let adx14 = json!({ "kind": "func", "name": "adx", "field": "close", "period": 14 });
    let close = json!({ "kind": "field", "field": "close" });

    StrategySeed {
        name: "momentum cascade",
        version: 2,
        description: "\
## Momentum Cascade

Stack several momentum signals in sequence — each must confirm before the next is checked.

**Cascade**:
1. **Trend filter**: EMA(50) > EMA(200) — long-term uptrend
2. **Momentum confirmation**: ADX(14) > 25 — trending, not ranging
3. **Entry trigger**: close crosses above EMA(20)

**Exit**: close crosses below EMA(20).",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Entry: trend filter + ADX momentum + EMA(20) crossover",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "compare", "left": ema50.clone(), "op": ">", "right": ema200.clone() },
                            { "kind": "compare", "left": adx14.clone(), "op": ">", "right": { "kind": "literal", "value": "25" } },
                            { "kind": "cross_over", "left": close.clone(), "right": ema20.clone() }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: close crosses below EMA(20)",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            { "kind": "cross_under", "left": close, "right": ema20 }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn gaussian_channel() -> StrategySeed {
    // 4-pole EMA approximation of a Gaussian filter via nested apply_func.
    // Band = 4-pole-EMA ± 1.6 × ATR(14).
    // Entry: close > upper band AND slope positive (4-pole-EMA > 4-pole-EMA[1]).
    // Exit: close < lower band OR slope negative.
    let ema1 = json!({ "kind": "func", "name": "ema", "field": "close", "period": 20 });
    let ema2 = json!({ "kind": "apply_func", "name": "ema", "input": ema1.clone(), "period": 20 });
    let ema3 = json!({ "kind": "apply_func", "name": "ema", "input": ema2.clone(), "period": 20 });
    let ema4 = json!({ "kind": "apply_func", "name": "ema", "input": ema3.clone(), "period": 20 });
    let ema4_prev = json!({ "kind": "apply_func", "name": "ema", "input": ema3.clone(), "period": 20, "offset": 1 });
    let atr14 = json!({ "kind": "func", "name": "atr", "field": "close", "period": 14 });
    let band_width = json!({
        "kind": "bin_op", "op": "mul",
        "left": { "kind": "literal", "value": "1.6" },
        "right": atr14.clone()
    });
    let upper_band = json!({ "kind": "bin_op", "op": "add", "left": ema4.clone(), "right": band_width.clone() });
    let lower_band = json!({ "kind": "bin_op", "op": "sub", "left": ema4.clone(), "right": band_width });
    let close = json!({ "kind": "field", "field": "close" });

    StrategySeed {
        name: "gaussian channel",
        version: 2,
        description: "\
## Gaussian Channel

Based on the Gaussian Channel indicator (DonovanWall). A true Gaussian filter is approximated
by applying EMA through itself 4 times (4-pole EMA, period 20).

**Band**: 4-pole-EMA ± 1.6 × ATR(14)

**Entry**: close > upper band AND 4-pole-EMA slope positive (value > previous bar)
**Exit**: close < lower band OR slope turns negative.",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Entry: close above upper Gaussian band and filter rising",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "compare", "left": close.clone(), "op": ">", "right": upper_band.clone() },
                            { "kind": "compare", "left": ema4.clone(), "op": ">", "right": ema4_prev.clone() }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: close below lower band or filter declining",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            {
                                "kind": "any_of",
                                "conditions": [
                                    { "kind": "compare", "left": close, "op": "<", "right": lower_band },
                                    { "kind": "compare", "left": ema4, "op": "<", "right": ema4_prev }
                                ]
                            }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn supertrend() -> StrategySeed {
    // Supertrend(10, 3.0): close crosses above = bullish entry, crosses below = exit.
    let supertrend_line = json!({ "kind": "func", "name": "supertrend", "field": "close", "period": 10, "multiplier": "3.0" });
    let close = json!({ "kind": "field", "field": "close" });

    StrategySeed {
        name: "supertrend",
        version: 2,
        description: "\
## Supertrend

A popular trend-following indicator that uses ATR to define a trailing stop-like line.

**Calculation**: ATR(10) with multiplier 3.0. The band flips between upper and lower
based on whether close is above or below the current band.

**Entry**: close crosses above the supertrend line (bullish flip).
**Exit**: close crosses below the supertrend line (bearish flip).",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Entry: close crosses above supertrend (bullish flip)",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "cross_over", "left": close.clone(), "right": supertrend_line.clone() }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: close crosses below supertrend (bearish flip)",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            { "kind": "cross_under", "left": close, "right": supertrend_line }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn money_line() -> StrategySeed {
    // VWAP(20) = sum(close × volume, 20) / sum(volume, 20) via apply_func + bin_op.
    // Entry: close crosses above VWAP(20) AND volume > 1.5 × SMA(volume, 20).
    // Exit: close crosses below VWAP(20).
    let cv = json!({
        "kind": "bin_op", "op": "mul",
        "left":  { "kind": "field", "field": "close" },
        "right": { "kind": "field", "field": "volume" }
    });
    let sum_cv  = json!({ "kind": "apply_func", "name": "sum", "input": cv, "period": 20 });
    let sum_vol = json!({ "kind": "apply_func", "name": "sum", "input": { "kind": "field", "field": "volume" }, "period": 20 });
    let vwap = json!({ "kind": "bin_op", "op": "div", "left": sum_cv, "right": sum_vol.clone() });
    let sma_vol = json!({ "kind": "func", "name": "sma", "field": "volume", "period": 20 });
    let vol_threshold = json!({
        "kind": "bin_op", "op": "mul",
        "left": { "kind": "literal", "value": "1.5" },
        "right": sma_vol
    });
    let close = json!({ "kind": "field", "field": "close" });
    let volume = json!({ "kind": "field", "field": "volume" });

    StrategySeed {
        name: "money line",
        version: 2,
        description: "\
## Money Line

A dynamic support/resistance line derived from volume-weighted price action.

**Money line**: 20-period rolling VWAP = sum(close × volume, 20) / sum(volume, 20).

**Entry**: close crosses above VWAP(20) with volume confirmation (volume > 1.5× SMA(vol, 20)).
**Exit**: close crosses below VWAP(20).",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Entry: close crosses above VWAP with volume confirmation",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "cross_over", "left": close.clone(), "right": vwap.clone() },
                            { "kind": "compare", "left": volume, "op": ">", "right": vol_threshold }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: close crosses below VWAP",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            { "kind": "cross_under", "left": close, "right": vwap }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn trend_detector() -> StrategySeed {
    // Hull MA(16) = WMA(2×WMA(close,8) − WMA(close,16), 4)  [sqrt(16)=4]
    // Entry: HMA rising (HMA > HMA[1]) AND close > HMA.
    // Exit: HMA declining OR close < HMA.
    let wma8  = json!({ "kind": "func", "name": "wma", "field": "close", "period": 8 });
    let wma16 = json!({ "kind": "func", "name": "wma", "field": "close", "period": 16 });
    let two_wma8 = json!({ "kind": "bin_op", "op": "mul", "left": { "kind": "literal", "value": "2" }, "right": wma8 });
    let diff = json!({ "kind": "bin_op", "op": "sub", "left": two_wma8, "right": wma16 });
    let hma16 = json!({ "kind": "apply_func", "name": "wma", "input": diff.clone(), "period": 4 });
    let hma16_prev = json!({ "kind": "apply_func", "name": "wma", "input": diff, "period": 4, "offset": 1 });
    let close = json!({ "kind": "field", "field": "close" });

    StrategySeed {
        name: "trend detector",
        version: 2,
        description: "\
## Trend Detector

Based on the Hull Moving Average (HMA) by Alan Hull — reduces lag while maintaining smoothness.

**HMA(16)** = WMA(2 × WMA(close, 8) − WMA(close, 16), 4)

**Entry**: HMA rising (HMA > HMA[1]) AND close > HMA.
**Exit**: HMA declining OR close < HMA.",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Entry: HMA(16) rising and close above HMA",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "compare", "left": hma16.clone(), "op": ">", "right": hma16_prev.clone() },
                            { "kind": "compare", "left": close.clone(), "op": ">", "right": hma16.clone() }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: HMA(16) declining or close below HMA",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            {
                                "kind": "any_of",
                                "conditions": [
                                    { "kind": "compare", "left": hma16.clone(), "op": "<", "right": hma16_prev },
                                    { "kind": "compare", "left": close, "op": "<", "right": hma16 }
                                ]
                            }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn stochastic_keltner() -> StrategySeed {
    // Keltner: EMA(20) ± 2×ATR(10). Stochastic %K = (close - lowest(low,14)) / (highest(high,14) - lowest(low,14)) × 100.
    // Entry: close > Keltner upper AND stoch crosses up from <20.
    // Exit: stoch > 80 OR close < EMA(20).
    let ema20  = json!({ "kind": "func", "name": "ema", "field": "close", "period": 20 });
    let atr10  = json!({ "kind": "func", "name": "atr", "field": "close", "period": 10 });
    let kelt_upper = json!({
        "kind": "bin_op", "op": "add",
        "left": ema20.clone(),
        "right": { "kind": "bin_op", "op": "mul", "left": { "kind": "literal", "value": "2" }, "right": atr10.clone() }
    });

    let lowest14  = json!({ "kind": "func", "name": "lowest",  "field": "low",  "period": 14 });
    let highest14 = json!({ "kind": "func", "name": "highest", "field": "high", "period": 14 });
    let close     = json!({ "kind": "field", "field": "close" });

    // %K = (close - lowest14) / (highest14 - lowest14) × 100
    let stoch_k = json!({
        "kind": "bin_op", "op": "mul",
        "left": {
            "kind": "bin_op", "op": "div",
            "left": { "kind": "bin_op", "op": "sub", "left": close.clone(), "right": lowest14.clone() },
            "right": { "kind": "bin_op", "op": "sub", "left": highest14.clone(), "right": lowest14.clone() }
        },
        "right": { "kind": "literal", "value": "100" }
    });

    let lowest14_p1  = json!({ "kind": "func", "name": "lowest",  "field": "low",  "period": 14, "offset": 1 });
    let highest14_p1 = json!({ "kind": "func", "name": "highest", "field": "high", "period": 14, "offset": 1 });
    let close_p1     = json!({ "kind": "field", "field": "close", "offset": 1 });
    let stoch_k_prev = json!({
        "kind": "bin_op", "op": "mul",
        "left": {
            "kind": "bin_op", "op": "div",
            "left": { "kind": "bin_op", "op": "sub", "left": close_p1, "right": lowest14_p1.clone() },
            "right": { "kind": "bin_op", "op": "sub", "left": highest14_p1.clone(), "right": lowest14_p1 }
        },
        "right": { "kind": "literal", "value": "100" }
    });

    StrategySeed {
        name: "stochastic + keltner",
        version: 2,
        description: "\
## Stochastic + Keltner Channel

A swing trading strategy combining Keltner Channels for trend direction with Stochastic %K for entry timing.

**Keltner Channel**: EMA(20) ± 2 × ATR(10)
**Stochastic %K**: (close − lowest(low, 14)) / (highest(high, 14) − lowest(low, 14)) × 100

**Entry**: price above upper Keltner band (bullish regime) AND %K crosses up from oversold (<20).
**Exit**: %K overbought (>80) OR price breaks below EMA(20).",
        config: json!({
            "type": "rule_based",
            "candle_interval": "4h",
            "rules": [
                {
                    "comment": "Entry: bullish Keltner regime AND stochastic crosses up from oversold",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "compare", "left": close.clone(), "op": ">", "right": kelt_upper },
                            { "kind": "compare", "left": stoch_k_prev, "op": "<", "right": { "kind": "literal", "value": "20" } },
                            { "kind": "compare", "left": stoch_k.clone(), "op": ">", "right": { "kind": "literal", "value": "20" } }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: stochastic overbought or price below EMA(20)",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            {
                                "kind": "any_of",
                                "conditions": [
                                    { "kind": "compare", "left": stoch_k, "op": ">", "right": { "kind": "literal", "value": "80" } },
                                    { "kind": "compare", "left": close, "op": "<", "right": ema20 }
                                ]
                            }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn hull_suite() -> StrategySeed {
    // HMA(9) = WMA(2×WMA(close,4) − WMA(close,9), 3)  [floor(sqrt(9))=3]
    // Band: HMA ± ATR(14).
    // Entry: close > upper band AND HMA rising.
    // Exit: close < lower band OR HMA declining.
    let wma4 = json!({ "kind": "func", "name": "wma", "field": "close", "period": 4 });
    let wma9 = json!({ "kind": "func", "name": "wma", "field": "close", "period": 9 });
    let two_wma4 = json!({ "kind": "bin_op", "op": "mul", "left": { "kind": "literal", "value": "2" }, "right": wma4 });
    let diff = json!({ "kind": "bin_op", "op": "sub", "left": two_wma4, "right": wma9 });
    let hma9      = json!({ "kind": "apply_func", "name": "wma", "input": diff.clone(), "period": 3 });
    let hma9_prev = json!({ "kind": "apply_func", "name": "wma", "input": diff, "period": 3, "offset": 1 });
    let atr14  = json!({ "kind": "func", "name": "atr", "field": "close", "period": 14 });
    let upper  = json!({ "kind": "bin_op", "op": "add", "left": hma9.clone(), "right": atr14.clone() });
    let lower  = json!({ "kind": "bin_op", "op": "sub", "left": hma9.clone(), "right": atr14 });
    let close  = json!({ "kind": "field", "field": "close" });

    StrategySeed {
        name: "hull suite",
        version: 2,
        description: "\
## Hull Suite

Based on the Hull Moving Average by Alan Hull. HMA reduces lag while maintaining smoothness.

**HMA(9)** = WMA(2 × WMA(close, 4) − WMA(close, 9), 3)
**Band**: HMA ± ATR(14)

**Entry**: close > upper band AND HMA rising (HMA > HMA[1]).
**Exit**: close < lower band OR HMA declining.",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Entry: close above HMA upper band and HMA rising",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "compare", "left": close.clone(), "op": ">", "right": upper },
                            { "kind": "compare", "left": hma9.clone(), "op": ">", "right": hma9_prev.clone() }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: close below HMA lower band or HMA declining",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            {
                                "kind": "any_of",
                                "conditions": [
                                    { "kind": "compare", "left": close, "op": "<", "right": lower },
                                    { "kind": "compare", "left": hma9, "op": "<", "right": hma9_prev }
                                ]
                            }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn supertrend_fusion() -> StrategySeed {
    // Three-layer filter inspired by SuperTrend Fusion (TradingView: Qe9aWBlF):
    //   1. SuperTrend(10, 3.0)    — trend direction
    //   2. Average Force ≈ Stoch %K(14) on close prices — momentum (where is close in recent range?)
    //      Smoothed with EMA(3) via apply_func to reduce noise.
    //   3. ADX(14) > 20           — choppiness filter (original uses Choppiness Index;
    //      ADX is the DSL-native equivalent: ADX > 20 = trending, ≤ 20 = ranging/choppy)
    //
    // Entry long: SuperTrend bullish flip AND smoothed momentum > 50 AND ADX > 20
    // Exit: SuperTrend bearish flip

    let supertrend_line = json!({
        "kind": "func", "name": "supertrend", "field": "close", "period": 10, "multiplier": "3.0"
    });

    // Average Force: raw %K = (close - lowest(close,14)) / (highest(close,14) - lowest(close,14)) * 100
    let lowest14c  = json!({ "kind": "func", "name": "lowest",  "field": "close", "period": 14 });
    let highest14c = json!({ "kind": "func", "name": "highest", "field": "close", "period": 14 });
    let close_field = json!({ "kind": "field", "field": "close" });

    let raw_af = json!({
        "kind": "bin_op", "op": "mul",
        "left": {
            "kind": "bin_op", "op": "div",
            "left":  { "kind": "bin_op", "op": "sub", "left": close_field, "right": lowest14c },
            "right": { "kind": "bin_op", "op": "sub", "left": highest14c, "right": {
                "kind": "func", "name": "lowest", "field": "close", "period": 14
            }}
        },
        "right": { "kind": "literal", "value": "100" }
    });

    // Smooth raw_af with EMA(3) via apply_func
    let af_smooth = json!({ "kind": "apply_func", "name": "ema", "input": raw_af, "period": 3 });

    let adx14 = json!({ "kind": "func", "name": "adx", "field": "close", "period": 14 });
    let close = json!({ "kind": "field", "field": "close" });

    StrategySeed {
        name: "supertrend fusion",
        version: 1,
        description: "\
## Supertrend Fusion

Inspired by the SuperTrend Fusion indicator (TradingView: Qe9aWBlF) which fuses trend,
momentum, and a volatility/choppiness filter to reduce false SuperTrend reversals.

**Three-layer filter**:
1. **Trend** — SuperTrend(10, 3.0): bullish when close > supertrend line
2. **Momentum (Average Force)** — EMA(3) of Stochastic %K(14) on close prices.
   Measures where close sits within its recent 14-bar range, smoothed. >50 = bullish momentum.
   (The original Average Force is a proprietary adaptation; this is a faithful open approximation.)
3. **Choppiness filter** — ADX(14) > 20: confirms trending conditions, filters sideways markets.
   (Original uses Choppiness Index; ADX is the DSL-native equivalent.)

**Entry**: SuperTrend flips bullish (close crosses above line) AND smoothed AF > 50 AND ADX > 20.
**Exit**: SuperTrend flips bearish (close crosses below line).",
        config: json!({
            "type": "rule_based",
            "candle_interval": "1h",
            "rules": [
                {
                    "comment": "Entry: SuperTrend bullish flip + positive momentum + trending regime",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "flat" },
                            { "kind": "cross_over", "left": close.clone(), "right": supertrend_line.clone() },
                            { "kind": "compare", "left": af_smooth, "op": ">", "right": { "kind": "literal", "value": "50" } },
                            { "kind": "compare", "left": adx14, "op": ">", "right": { "kind": "literal", "value": "20" } }
                        ]
                    },
                    "then": { "side": "buy", "quantity": "0.001" }
                },
                {
                    "comment": "Exit: SuperTrend bearish flip",
                    "when": {
                        "kind": "all_of",
                        "conditions": [
                            { "kind": "position", "state": "long" },
                            { "kind": "cross_under", "left": close, "right": supertrend_line }
                        ]
                    },
                    "then": { "side": "sell", "quantity": "0.001" }
                }
            ]
        }),
    }
}

fn emmanuel_ma_v2() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 2,
        description: "\
## Emmanuel MA Pullback v2

A refined 20/200 SMA pullback strategy on the 4-hour chart. Builds on v1 with two key
improvements: the not-first-touch guard now uses `event_count` to directly detect a prior
`cross_under` of the 20 SMA within the last 30 bars (rather than a price-level proxy), and
a `bars_since` recency guard filters same-candle-cluster whipsaws by requiring the last
cross_under to be more than 1 bar ago.

Also adds explicit slope filters: the 20 SMA must be rising (current > 5 bars ago) and
the 200 SMA must be rising (current > 10 bars ago). Volume confirmation requires the
entry bar volume to exceed its 20-bar average.

**Entry**: 9-condition all_of — bounce cross_over + trend stack + slope filters
  + overextension guard + event_count not-first-touch + bars_since recency guard
  + clean pullback + volume spike.

**Exit 1** (primary): close crosses back below the 20 SMA.
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v2.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v2.json is valid JSON"),
    }
}

fn emmanuel_ma_v8() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 8,
        description: "\
## Emmanuel MA Pullback v8

Adds two new filters to v7's proximity-and-rising entry: ADX(14) > 20 (trend
strength — avoids choppy sideways markets) and an impulsive-move check
(highest(high, 20) at least 3% above 20 SMA, confirming a real thrust preceded
the pullback). Exit unchanged from v7.

**Entry**: 10-condition all_of — trend stack + 20 SMA slope + overextension guard
  + ADX > 20 + impulsive move + proximity above (≥ sma20, within 1.5%)
  + rising price + pullback evidence + clean touch (3%).

**Exit 1** (trailing): close crosses below 50 SMA.
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v8.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v8.json is valid JSON"),
    }
}

fn emmanuel_mtf_v2() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MTF",
        version: 2,
        description: "\
## Emmanuel MTF — Multi-Timeframe SMA Pullback v2

Fixes the fatal bottleneck in v1 identified by condition audit: the not-first-touch \
filter (condition 11) had a 7.0% pass rate and misread the transcript. Emmanuel says \
to skip the first touch AFTER a parabolic run — not to require proof of a prior \
impulse. v2 replaces it with a not-parabolic guard: entry is blocked when close is \
already >3% above the 15m 20 SMA, which is the actual case Emmanuel describes avoiding.

Also adds ADX(14) > 20 on the 4h timeframe to compensate for the removed selectivity, \
and widens the pullback-evidence tolerance from 0.3% to 0.5% (was the next tightest \
filter at 46.9% pass rate in v1).

**4h (trend context):** Bullish regime — 20/200 SMA stack, rising 20 SMA, price above \
20 SMA, not extended, ADX > 20 (trending market).

**15m (entry timing):** Rising 20 SMA, close just above it (≤ 0.5%), not parabolic \
(< 3% above SMA), price rising, recent low touched the SMA within 0.5%.

**Entry**: 12-condition all_of — 4h trend stack + ADX + 15m timing + not-parabolic guard.

**Exit 1** (trailing): close crosses below the 15m 20 SMA.
**Exit 2** (structural): 4h 20 SMA crosses below 4h 200 SMA (macro trend broken).
**Exit 3** (hard stop): close drops more than 2% below the 15m 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-mtf/v2.json"),
        )
        .expect("assets/strategy/emmanuel-mtf/v2.json is valid JSON"),
    }
}

fn emmanuel_mtf_v3() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MTF",
        version: 3,
        description: "\
## Emmanuel MTF — Multi-Timeframe SMA Pullback v3

Driven by v2's condition audit (179 trades, 19% win rate, profit factor 0.586 over 360 days). \
Root cause: no upside exit (all exits were downside), ADX filter too loose (71.9% pass), and \
cross_under exit fired on single-bar noise. To break even at 19% win rate requires ~4.3× average \
win/loss; the strategy needs either a higher win rate or banked profit targets.

**Changes from v2:**

1. **Take-profit exit** (new): sell when close is >1.5% above 15m 20 SMA. The most impactful \
change — v2 had no upside exit so every winner had to survive a full reversal.

2. **Trailing stop tightened**: replaced cross_under with a compare requiring close 0.1% below \
SMA. Single-bar noise trips the cross_under; a small threshold absorbs it.

3. **Bullish entry candle** (new): requires close > open on the 15m bar at entry — proxy for \
Emmanuel's candle-structure read at the MA touch.

4. **4h SMA rising check tightened**: offset 5 → 2 (20 hours → 8 hours). An MA that was rising \
20 hours ago can be turning flat now; this requires momentum to be current.

5. **ADX threshold raised**: 20 → 25. v2 audit showed ADX>20 passing 71.9% of bars — barely \
selective. >25 focuses on genuinely trending regimes.

**4h (trend context):** 20/200 SMA stack, recently rising 20 SMA (8h window), price above 20 SMA, \
not extended, ADX > 25.

**15m (entry timing):** Rising 20 SMA, bullish candle, close just above (≤ 0.5%), not parabolic, \
price rising, recent low touched SMA within 0.5%.

**Entry**: 13-condition all_of.

**Exit 1** (trailing stop): close drops 0.1% below 15m 20 SMA.
**Exit 2** (take-profit): close rises 1.5% above 15m 20 SMA.
**Exit 3** (structural): 4h 20 SMA crosses below 4h 200 SMA.
**Exit 4** (hard stop): close drops 2% below 15m 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-mtf/v3.json"),
        )
        .expect("assets/strategy/emmanuel-mtf/v3.json is valid JSON"),
    }
}

fn emmanuel_mtf_v4() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MTF",
        version: 4,
        description: "\
## Emmanuel MTF — Multi-Timeframe SMA Pullback v4

Driven by v3 audit (127 trades, 21.26% win rate, profit factor 0.686). Take-profit \
fired only 11 times (8.7% of exits) — most trades never reached +1.5% before reversing. \
The 15m entry conditions pass at ~50% (coin-flips) because the 15m itself may be in a \
local downtrend even when the 4h is bullish.

**Changes from v3:**

1. **15m SMA stack** (new): requires SMA(20,15m) > SMA(200,15m). Forces triple alignment — \
4h bull regime AND 15m local bull regime AND pullback to 15m 20 SMA. Without this, entries \
happen when the 15m 20 SMA is acting as resistance in a local downtrend.

2. **Entry proximity tightened**: 0.5% → 0.3%. Entries closer to the SMA mean smaller losses \
when the trade fails and better risk/reward toward the take-profit target.

3. **Take-profit lowered**: 1.5% → 1.0% above 15m 20 SMA. v3 take-profit only caught 8.7% \
of trades; lowering captures more exits before reversal while still representing meaningful gain.

**4h (trend context):** 20/200 SMA stack, rising 20 SMA (8h window), price above 20 SMA, \
not extended, ADX > 25.

**15m (entry timing):** 15m 20 SMA > 15m 200 SMA (local bull), rising 20 SMA, bullish \
candle, close just above (≤ 0.3%), not parabolic, price rising, recent low touched SMA.

**Entry**: 14-condition all_of.

**Exit 1** (trailing stop): close drops 0.1% below 15m 20 SMA.
**Exit 2** (take-profit): close rises 1.0% above 15m 20 SMA.
**Exit 3** (structural): 4h 20 SMA crosses below 4h 200 SMA.
**Exit 4** (hard stop): close drops 2% below 15m 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-mtf/v4.json"),
        )
        .expect("assets/strategy/emmanuel-mtf/v4.json is valid JSON"),
    }
}

fn emmanuel_mtf_v1() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MTF",
        version: 1,
        description: "\
## Emmanuel MTF — Multi-Timeframe SMA Pullback Strategy

Inspired by Emmanuel Malyarovich's approach using only two indicators — the 20 SMA \
and 200 SMA — applied across multiple timeframes. The higher timeframe establishes \
trend direction; the lower timeframe times entries at pullbacks to the 20 SMA.

**4h (trend context):** Confirms a bullish regime — close above the 200 SMA, 20 SMA \
stacked above the 200 and rising, price above the 20 SMA but not overextended from it.

**15m (entry timing):** Waits for price to retrace to the 15m 20 SMA and bounce. \
Requires the MA to be rising, price to be in a tight proximity zone just above it, \
evidence of an actual pullback (low touched the MA recently), and evidence of a prior \
impulsive move (recent high was meaningfully above the MA — avoids first-touch traps \
after exhaustion moves).

**Entry**: 11-condition all_of — 4h trend stack (close > 200 SMA, 20 SMA > 200 SMA, \
  rising 20 SMA, price > 20 SMA, not overextended < 5%) + 15m entry (rising 20 SMA, \
  close ≥ 20 SMA, proximity within 0.5%, price rising, pullback touch within 0.3%, \
  prior impulsive move > 1.5%).

**Exit 1** (trailing): close crosses below the 15m 20 SMA.
**Exit 2** (structural): 4h 20 SMA crosses below 4h 200 SMA (macro trend broken).
**Exit 3** (hard stop): close drops more than 2% below the 15m 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-mtf/v1.json"),
        )
        .expect("assets/strategy/emmanuel-mtf/v1.json is valid JSON"),
    }
}

fn emmanuel_ma_v7() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 7,
        description: "\
## Emmanuel MA Pullback v7

Same proximity-and-rising entry as v6. Drops the 3-bar minimum hold on exit:
the 50 SMA is slow enough to avoid whipsaw without it.

**Entry**: 8-condition all_of — trend stack + 20 SMA slope + overextension guard
  + proximity above (≥ sma20, within 1.5%) + rising price + pullback evidence
  + clean touch (3%).

**Exit 1** (trailing): close crosses below 50 SMA (no minimum hold).
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v7.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v7.json is valid JSON"),
    }
}

fn emmanuel_ma_v6() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 6,
        description: "\
## Emmanuel MA Pullback v6

Replaces the cross_over entry trigger with a proximity-and-rising approach:
close must be above the 20 SMA, within 1.5% of it, and rising (close > close[2]).
Pullback evidence required: lowest(low, 5) within 1% of the 20 SMA. Drops
event_count and bars_since guards (proximity implies a prior touch implicitly).
Exit unchanged from v5: 50 SMA trailing with 3-bar minimum hold, hard stop at 4%.

**Entry**: 8-condition all_of — trend stack + 20 SMA slope + overextension guard
  + proximity above (≥ sma20, within 1.5%) + rising price + pullback evidence
  + clean touch (3%).

**Exit 1** (trailing): close crosses below 50 SMA AND ≥ 3 bars since entry zone.
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v6.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v6.json is valid JSON"),
    }
}

fn emmanuel_ma_v5() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 5,
        description: "\
## Emmanuel MA Pullback v5

Same entry as v4 (4h, v3 relaxations). Exit reworked to give winners more room:
trailing exit moved from 20 SMA to 50 SMA, with a minimum 3-bar hold before it
can fire. Hard stop (4% below 20 SMA) has no minimum hold.

**Entry**: 9-condition all_of — bounce cross_over + trend stack + 20 SMA slope filter
  + overextension guard + event_count not-first-touch + bars_since recency guard
  + clean touch (3%) + volume confirmation (0.8×).

**Exit 1** (trailing): close crosses below 50 SMA AND ≥ 3 bars since entry.
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v5.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v5.json is valid JSON"),
    }
}

fn emmanuel_ma_v4() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 4,
        description: "\
## Emmanuel MA Pullback v4

Returns to 4h candles (v3's 1h caused exit whipsaw). Carries v3's filter relaxations:
200 SMA rising check removed, clean touch widened to 3%, volume softened to 0.8×,
recency guard relaxed to > 0 bars.

**Entry**: 9-condition all_of — bounce cross_over + trend stack + 20 SMA slope filter
  + overextension guard + event_count not-first-touch + bars_since recency guard
  + clean touch (3%) + volume confirmation (0.8×).

**Exit 1** (primary): close crosses back below the 20 SMA.
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v4.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v4.json is valid JSON"),
    }
}

fn emmanuel_ma_v3() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 3,
        description: "\
## Emmanuel MA Pullback v3

Drops to the 1-hour chart for more trigger opportunities. Key relaxations over v2:
200 SMA rising check removed (redundant with MA stacking), clean touch widened to 3%,
volume filter softened to 0.8× average, recency guard relaxed to > 0 bars.

**Entry**: 9-condition all_of — bounce cross_over + trend stack + 20 SMA slope filter
  + overextension guard + event_count not-first-touch + bars_since recency guard
  + clean touch (3%) + volume confirmation (0.8×).

**Exit 1** (primary): close crosses back below the 20 SMA.
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v3.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v3.json is valid JSON"),
    }
}

fn emmanuel_ma() -> StrategySeed {
    StrategySeed {
        name: "Emmanuel MA",
        version: 1,
        description: "\
## Emmanuel MA Pullback

A 20/200 SMA pullback strategy on the 4-hour chart. Enters long when price
pulls back to the rising 20 SMA in a confirmed uptrend (close and 20 SMA both
above the rising 200 SMA), then bounces back above the 20 SMA with volume
confirmation. Requires the pullback to be shallow (within 1.5% below the 20 SMA)
and the position not overextended (within 8% above the 200 SMA). Also checks that
this is not the first test of the MA (prior touch within 20 bars).

**Entry**: 10-condition all_of gate — bounce cross_over + trend stack + slope filters
  + overextension guard + clean pullback + prior-touch proxy + volume spike.

**Exit 1** (primary): close crosses back below the 20 SMA.
**Exit 2** (structural): 20 SMA crosses below 200 SMA (trend inverted).
**Exit 3** (hard stop): close drops more than 4% below the 20 SMA.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/emmanuel-ma/v1.json"),
        )
        .expect("assets/strategy/emmanuel-ma/v1.json is valid JSON"),
    }
}

// ---------------------------------------------------------------------------
// Revised strategy seeds (v2/v3 — use assets/strategy/<name>/ JSON files)
// ---------------------------------------------------------------------------

fn simple_trend_v2() -> StrategySeed {
    StrategySeed {
        name: "simple trend + regime filter",
        version: 2,
        description: "\
## Simple Trend + Regime Filter v2

Adds an ADX(14) > 25 regime gate to v1's EMA(20/50) crossover signal.
Only takes trend signals when the market is confirmed trending (ADX > 25),
filtering out the whipsaw crossovers that occur in ranging conditions.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/simple-trend/v2.json"),
        )
        .expect("assets/strategy/simple-trend/v2.json is valid JSON"),
    }
}

fn buy_2_factors_reversion_v2() -> StrategySeed {
    StrategySeed {
        name: "buy 2 factors, reversion entry",
        version: 2,
        description: "\
## Buy 2 Factors, Reversion Entry v2

Completes the originally-intended 3-factor gate by adding ADX(14) > 20 as Factor 2.

**Entry**: RSI(14) < 30 AND close > SMA(200) AND ADX(14) > 20.
**Exit**: RSI(14) > 70 (unchanged from v1).",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/buy-2-factors/v2.json"),
        )
        .expect("assets/strategy/buy-2-factors/v2.json is valid JSON"),
    }
}

fn ichimoku_v2() -> StrategySeed {
    StrategySeed {
        name: "ichimoku",
        version: 2,
        description: "\
## Ichimoku Kinko Hyo v2

Adds two additional entry filters to v1's core TK crossover:
1. **Chikou Span**: current close > close 26 bars ago — lagging line confirms upward momentum.
2. **Cloud colour**: Senkou Span A > Span B at current bar — bullish cloud at time of entry.

Exit unchanged from v1 (Tenkan crosses below Kijun).",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/ichimoku/v2.json"),
        )
        .expect("assets/strategy/ichimoku/v2.json is valid JSON"),
    }
}

fn bull_market_support_band_v2() -> StrategySeed {
    StrategySeed {
        name: "bull market support band",
        version: 2,
        description: "\
## Bull Market Support Band v2

Adds explicit bull market confirmation using `event_count`: requires at least
35 of the last 50 daily closes to be above SMA(100) before a band bounce entry
is accepted. This prevents entries during bear market dead-cat bounces.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/bull-market-support-band/v2.json"),
        )
        .expect("assets/strategy/bull-market-support-band/v2.json is valid JSON"),
    }
}

fn supertrend_v3() -> StrategySeed {
    StrategySeed {
        name: "supertrend",
        version: 3,
        description: "\
## Supertrend v3

Adds ADX(14) > 25 regime gate to v2's Supertrend crossover signal.
Avoids entering on Supertrend flips that occur during sideways, choppy markets.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/supertrend/v3.json"),
        )
        .expect("assets/strategy/supertrend/v3.json is valid JSON"),
    }
}

fn gaussian_channel_v3() -> StrategySeed {
    StrategySeed {
        name: "gaussian channel",
        version: 3,
        description: "\
## Gaussian Channel v3

Replaces the persistent `compare(close, >, upper_band)` entry condition with a
`cross_over` transition — the signal fires only on the bar where price first
breaks above the upper band. This avoids repeated re-entries while price remains
above the band and makes entries more precise.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/gaussian-channel/v3.json"),
        )
        .expect("assets/strategy/gaussian-channel/v3.json is valid JSON"),
    }
}

fn stochastic_keltner_v3() -> StrategySeed {
    StrategySeed {
        name: "stochastic + keltner",
        version: 3,
        description: "\
## Stochastic + Keltner Channel v3

Replaces the manual two-bar offset crossover simulation (`stoch[1] < 20 AND stoch > 20`)
with a proper `cross_over(stoch_k, literal(20))`. The semantics are identical but
the expression is cleaner and uses the intended DSL primitive.",
        config: serde_json::from_str(
            include_str!("../../../../assets/strategy/stochastic-keltner/v3.json"),
        )
        .expect("assets/strategy/stochastic-keltner/v3.json is valid JSON"),
    }
}
