Skip to main content
Glama

save_strategy

To promote a sweep pick, pass source_experiment_id and source_run_index; the service loads its authorized configuration and checks coverage before saving. Its recorded venue and quote token are defaults: pass market_data_venue and/or quote_token only when the person chooses a different market. Otherwise compose and save a trading strategy from signals in the library. Give it a strategy_name, an asset, and the entry and exit signals you chose -- each one {name, params?, timeframe?}, with params defaulting from the library when omitted. DO NOT pass a signal's role: TRIGGER and FILTER are read from the library, and an entry must resolve to exactly one TRIGGER plus any number of FILTERs. Find real signal names with query_knowledge first; never invent one. The server checks the entry against the current market regime itself -- a strategy composed against the wrong regime is refused, and telling the person why is a better answer than saving it anyway. Pass constraints for supported execution settings requested by the person or justified by the composition workflow after reading the execution-config contract. Preserve explicit user choices; explain agent-selected adjustments as recommendations, not as values the person requested. Supplied values are kept exactly, while omitted values use server defaults or the selected source run. Saving the same strategy twice returns the first one rather than making a duplicate, and says so in created. What you save is a DRAFT: not tradeable until a backtest of it meets the platform's threshold spec, and it leaves draft on its own when one does.

[Access: pay 0.005 USDC via x402 (PAYMENT-SIGNATURE header) OR authenticate with an API key. An x402-capable client will auto-pay; API-key clients pay nothing per call.]

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "asset": "<asset>",
      "strategy_name": "<strategy_name>"
    },
    "name": "save_strategy"
  }
}

Input Schema

NameRequiredDescriptionDefault
assetYesAsset symbol, e.g. BTC or ETH.
constraintsNoSupported execution overrides requested by the person or justified by the composition workflow after reading the execution-config contract. Preserve explicit user choices and explain agent-selected adjustments. Each supplied value is kept exactly as given rather than nudged.
quote_tokenNoQuote currency of the requested market.
exit_signalsNoThe signals that close one, same shape. A strategy may have none, and then it exits on risk rules alone.
entry_signalsNoThe signals that open a position. Exactly one must be a TRIGGER in the knowledge graph; the rest are FILTERs.
strategy_nameYesWhat to call it, in plain words a person reads -- the entry trigger's friendly_name from the knowledge graph, then the asset and timeframe, e.g. "Upside Range Breakout - BTC 1h". Never a code name such as btc_strategy or bb_upper_breakout.
regime_overrideNoSave anyway when the regime check refuses. Only ever on the person's explicit say-so, after they have been told why.
regime_directionNoThe direction band from get_market_regime, e.g. bear. The signal searches filter by it and find_sweep_runs marks each row's regime_fit with it; save_strategy and update_strategy read the current band themselves, so their check runs without it.
source_run_indexNoThe selected sweep row, including zero.
market_data_venueNoExact venue of the requested market.
source_config_hashNoThe selected row's config_hash, as find_sweep_runs reported it. Pass it with the other two: a relaunched sweep can give one run_index to several runs, and without it such an index is refused.
source_experiment_idNoFor a sweep pick, its experiment ID. Supply with source_run_index. The stored run supplies the exact signals and execution settings. With no market given, it saves on the run's market when ref-data lists it, otherwise on a market ref-data lists, the run's venue first.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • changedInput schema / properties / constraints / description
      Previous value: -"Execution values the person stated, e.g. {\"max_risk_per_trade\": 0.01}. Each is kept exactly as given rather than nudged."New value: +"Supported execution overrides requested by the person or justified by the composition workflow after reading the execution-config contract. Preserve explicit user choices and explain agent-selected adjustments. Each supplied value is kept exactly as given rather than nudged."
    • changedInput schema / properties / constraints / properties / circuit_breaker / x-mangrove-authoring-schema / default / consecutive_loss_limit
      Previous value: -4New value: +2
    • changedInput schema / properties / constraints / properties / circuit_breaker / x-mangrove-authoring-schema / properties / consecutive_loss_limit / default
      Previous value: -4New value: +2
    • changedInput schema / properties / constraints / x-mangrove-authoring-schema / properties / circuit_breaker / default / consecutive_loss_limit
      Previous value: -4New value: +2
    • changedInput schema / properties / constraints / x-mangrove-authoring-schema / properties / circuit_breaker / properties / consecutive_loss_limit / default
      Previous value: -4New value: +2
  2. Changed1 schema field changed
    • changedInput schema / properties / source_experiment_id / description
      Previous value: -"For a sweep pick, its experiment ID. Supply with source_run_index. The stored run supplies the exact signals and execution settings. With no market given, it saves on the run's corpus market, or on the same venue's execution quote when the corpus quote is not one (Binance USDT saves as Binance USDC)."New value: +"For a sweep pick, its experiment ID. Supply with source_run_index. The stored run supplies the exact signals and execution settings. With no market given, it saves on the run's market when ref-data lists it, otherwise on a market ref-data lists, the run's venue first."
  3. Changed10 schema fields changed
    • removedInput schema / properties / constraints / properties / cooldown_bars
      Removed value: -{
      -  "description": "Bars to wait between trades on the same asset.",
      -  "x-mangrove-authoring-schema": {
      -    "default": 24,
      -    "description": "Bars to wait between trades on the same asset.",
      -    "maximum": 10000,
      -    "minimum": 0,
      -    "type": [
      -      "integer",
      -      "null"
      -    ],
      -    "x-mangrove-effect": "Higher spaces trades out (reduces overtrading and whipsaw); lower allows quicker re-entry.",
      -    "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      -    "x-mangrove-status": "tunable"
      -  }
      -}
    • removedInput schema / properties / constraints / properties / cooldown_config
      Removed value: -{
      -  "description": "Per-timeframe loss-streak cooldown windows (short/long loss limits and cooldown bar counts).",
      -  "x-mangrove-authoring-schema": {
      -    "additionalProperties": {
      -      "additionalProperties": true,
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "default": {
      -      "15m": {
      -        "long_cooldown_bars": 320,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 320,
      -        "short_cooldown_bars": 120,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 120
      -      },
      -      "1d": {
      -        "long_cooldown_bars": 60,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 60,
      -        "short_cooldown_bars": 20,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 20
      -      },
      -      "1h": {
      -        "long_cooldown_bars": 144,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 144,
      -        "short_cooldown_bars": 48,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 48
      -      },
      -      "30m": {
      -        "long_cooldown_bars": 220,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 220,
      -        "short_cooldown_bars": 80,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 80
      -      },
      -      "4h": {
      -        "long_cooldown_bars": 96,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 96,
      -        "short_cooldown_bars": 32,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 32
      -      },
      -      "5m": {
      -        "long_cooldown_bars": 480,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 480,
      -        "short_cooldown_bars": 180,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 180
      -      }
      -    },
      -    "description": "Per-timeframe loss-streak cooldown windows (short/long loss limits and cooldown bar counts).",
      -    "properties": {
      -      "15m": {
      -        "additionalProperties": true,
      -        "default": {
      -          "long_cooldown_bars": 320,
      -          "long_loss_limit": 6,
      -          "long_window_bars": 320,
      -          "short_cooldown_bars": 120,
      -          "short_loss_limit": 4,
      -          "short_window_bars": 120
      -        },
      -        "properties": {
      -          "long_cooldown_bars": {
      -            "default": 320,
      -            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_loss_limit": {
      -            "default": 6,
      -            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_window_bars": {
      -            "default": 320,
      -            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_cooldown_bars": {
      -            "default": 120,
      -            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_loss_limit": {
      -            "default": 4,
      -            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_window_bars": {
      -            "default": 120,
      -            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -            "x-mangrove-status": "tunable"
      -          }
      -        },
      -        "required": [
      -          "short_window_bars",
      -          "long_window_bars",
      -          "short_loss_limit",
      -          "long_loss_limit"
      -        ],
      -        "type": "object"
      -      },
      -      "1d": {
      -        "additionalProperties": true,
      -        "default": {
      -          "long_cooldown_bars": 60,
      -          "long_loss_limit": 6,
      -          "long_window_bars": 60,
      -          "short_cooldown_bars": 20,
      -          "short_loss_limit": 4,
      -          "short_window_bars": 20
      -        },
      -        "properties": {
      -          "long_cooldown_bars": {
      -            "default": 60,
      -            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_loss_limit": {
      -            "default": 6,
      -            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_window_bars": {
      -            "default": 60,
      -            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_cooldown_bars": {
      -            "default": 20,
      -            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_loss_limit": {
      -            "default": 4,
      -            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_window_bars": {
      -            "default": 20,
      -            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -            "x-mangrove-status": "tunable"
      -          }
      -        },
      -        "required": [
      -          "short_window_bars",
      -          "long_window_bars",
      -          "short_loss_limit",
      -          "long_loss_limit"
      -        ],
      -        "type": "object"
      -      },
      -      "1h": {
      -        "additionalProperties": true,
      -        "default": {
      -          "long_cooldown_bars": 144,
      -          "long_loss_limit": 6,
      -          "long_window_bars": 144,
      -          "short_cooldown_bars": 48,
      -          "short_loss_limit": 4,
      -          "short_window_bars": 48
      -        },
      -        "properties": {
      -          "long_cooldown_bars": {
      -            "default": 144,
      -            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_loss_limit": {
      -            "default": 6,
      -            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_window_bars": {
      -            "default": 144,
      -            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_cooldown_bars": {
      -            "default": 48,
      -            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_loss_limit": {
      -            "default": 4,
      -            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_window_bars": {
      -            "default": 48,
      -            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -            "x-mangrove-status": "tunable"
      -          }
      -        },
      -        "required": [
      -          "short_window_bars",
      -          "long_window_bars",
      -          "short_loss_limit",
      -          "long_loss_limit"
      -        ],
      -        "type": "object"
      -      },
      -      "30m": {
      -        "additionalProperties": true,
      -        "default": {
      -          "long_cooldown_bars": 220,
      -          "long_loss_limit": 6,
      -          "long_window_bars": 220,
      -          "short_cooldown_bars": 80,
      -          "short_loss_limit": 4,
      -          "short_window_bars": 80
      -        },
      -        "properties": {
      -          "long_cooldown_bars": {
      -            "default": 220,
      -            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_loss_limit": {
      -            "default": 6,
      -            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_window_bars": {
      -            "default": 220,
      -            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_cooldown_bars": {
      -            "default": 80,
      -            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_loss_limit": {
      -            "default": 4,
      -            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_window_bars": {
      -            "default": 80,
      -            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -            "x-mangrove-status": "tunable"
      -          }
      -        },
      -        "required": [
      -          "short_window_bars",
      -          "long_window_bars",
      -          "short_loss_limit",
      -          "long_loss_limit"
      -        ],
      -        "type": "object"
      -      },
      -      "4h": {
      -        "additionalProperties": true,
      -        "default": {
      -          "long_cooldown_bars": 96,
      -          "long_loss_limit": 6,
      -          "long_window_bars": 96,
      -          "short_cooldown_bars": 32,
      -          "short_loss_limit": 4,
      -          "short_window_bars": 32
      -        },
      -        "properties": {
      -          "long_cooldown_bars": {
      -            "default": 96,
      -            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_loss_limit": {
      -            "default": 6,
      -            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_window_bars": {
      -            "default": 96,
      -            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_cooldown_bars": {
      -            "default": 32,
      -            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_loss_limit": {
      -            "default": 4,
      -            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_window_bars": {
      -            "default": 32,
      -            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -            "x-mangrove-status": "tunable"
      -          }
      -        },
      -        "required": [
      -          "short_window_bars",
      -          "long_window_bars",
      -          "short_loss_limit",
      -          "long_loss_limit"
      -        ],
      -        "type": "object"
      -      },
      -      "5m": {
      -        "additionalProperties": true,
      -        "default": {
      -          "long_cooldown_bars": 480,
      -          "long_loss_limit": 6,
      -          "long_window_bars": 480,
      -          "short_cooldown_bars": 180,
      -          "short_loss_limit": 4,
      -          "short_window_bars": 180
      -        },
      -        "properties": {
      -          "long_cooldown_bars": {
      -            "default": 480,
      -            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_loss_limit": {
      -            "default": 6,
      -            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "long_window_bars": {
      -            "default": 480,
      -            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_cooldown_bars": {
      -            "default": 180,
      -            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_loss_limit": {
      -            "default": 4,
      -            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -            "x-mangrove-status": "tunable"
      -          },
      -          "short_window_bars": {
      -            "default": 180,
      -            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -            "maximum": 10000,
      -            "minimum": 1,
      -            "type": "integer",
      -            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -            "x-mangrove-status": "tunable"
      -          }
      -        },
      -        "required": [
      -          "short_window_bars",
      -          "long_window_bars",
      -          "short_loss_limit",
      -          "long_loss_limit"
      -        ],
      -        "type": "object"
      -      },
      -      "cadence_reference": {
      -        "description": "Server-selected strategy cadence; metadata rather than a timeframe entry.",
      -        "type": "string"
      -      }
      -    },
      -    "type": [
      -      "object",
      -      "null"
      -    ],
      -    "x-mangrove-effect": "Tighter limits pause trading sooner after a losing streak; looser limits keep trading through drawdowns.",
      -    "x-mangrove-map-value-schema": {
      -      "additionalProperties": true,
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "x-mangrove-status": "tunable"
      -  }
      -}
    • changedInput schema / properties / constraints / properties / cooldown_model / x-mangrove-authoring-schema / x-mangrove-effect
      Previous value: -"'trades' trips on trade count and loss size regardless of how far apart trades are spaced; 'bars' trips only when losses land inside the window. cooldown_config is ignored under 'trades'."New value: +"'trades' trips on trade count and loss size regardless of how far apart trades are spaced; 'bars' trips only when losses land inside the window. cooldown_config, cooldown_bars, daily_momentum_limit and weekly_momentum_limit are read only under 'bars': they are left out of a resolved config under 'trades', and a config that carries them under 'trades' has them dropped."
    • removedInput schema / properties / constraints / properties / daily_momentum_limit
      Removed value: -{
      -  "description": "Daily momentum-based trade limit.",
      -  "x-mangrove-authoring-schema": {
      -    "default": 3,
      -    "description": "Daily momentum-based trade limit.",
      -    "exclusiveMinimum": 0,
      -    "maximum": 100,
      -    "type": [
      -      "number",
      -      "null"
      -    ],
      -    "x-mangrove-effect": "Higher permits more momentum-driven entries per day; lower throttles them.",
      -    "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      -    "x-mangrove-status": "guardrail"
      -  }
      -}
    • removedInput schema / properties / constraints / properties / weekly_momentum_limit
      Removed value: -{
      -  "description": "Weekly momentum-based trade limit.",
      -  "x-mangrove-authoring-schema": {
      -    "default": 3,
      -    "description": "Weekly momentum-based trade limit.",
      -    "exclusiveMinimum": 0,
      -    "maximum": 100,
      -    "type": [
      -      "number",
      -      "null"
      -    ],
      -    "x-mangrove-effect": "Higher permits more momentum-driven entries per week; lower throttles them.",
      -    "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      -    "x-mangrove-status": "guardrail"
      -  }
      -}
    • removedInput schema / properties / constraints / x-mangrove-authoring-schema / properties / cooldown_bars
      Removed value: -{
      -  "default": 24,
      -  "description": "Bars to wait between trades on the same asset.",
      -  "maximum": 10000,
      -  "minimum": 0,
      -  "type": [
      -    "integer",
      -    "null"
      -  ],
      -  "x-mangrove-effect": "Higher spaces trades out (reduces overtrading and whipsaw); lower allows quicker re-entry.",
      -  "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      -  "x-mangrove-status": "tunable"
      -}
    • removedInput schema / properties / constraints / x-mangrove-authoring-schema / properties / cooldown_config
      Removed value: -{
      -  "additionalProperties": {
      -    "additionalProperties": true,
      -    "properties": {
      -      "long_cooldown_bars": {
      -        "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "long_loss_limit": {
      -        "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -        "maximum": 100,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "long_window_bars": {
      -        "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "short_cooldown_bars": {
      -        "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "short_loss_limit": {
      -        "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -        "maximum": 100,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "short_window_bars": {
      -        "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -        "x-mangrove-status": "tunable"
      -      }
      -    },
      -    "required": [
      -      "short_window_bars",
      -      "long_window_bars",
      -      "short_loss_limit",
      -      "long_loss_limit"
      -    ],
      -    "type": "object"
      -  },
      -  "default": {
      -    "15m": {
      -      "long_cooldown_bars": 320,
      -      "long_loss_limit": 6,
      -      "long_window_bars": 320,
      -      "short_cooldown_bars": 120,
      -      "short_loss_limit": 4,
      -      "short_window_bars": 120
      -    },
      -    "1d": {
      -      "long_cooldown_bars": 60,
      -      "long_loss_limit": 6,
      -      "long_window_bars": 60,
      -      "short_cooldown_bars": 20,
      -      "short_loss_limit": 4,
      -      "short_window_bars": 20
      -    },
      -    "1h": {
      -      "long_cooldown_bars": 144,
      -      "long_loss_limit": 6,
      -      "long_window_bars": 144,
      -      "short_cooldown_bars": 48,
      -      "short_loss_limit": 4,
      -      "short_window_bars": 48
      -    },
      -    "30m": {
      -      "long_cooldown_bars": 220,
      -      "long_loss_limit": 6,
      -      "long_window_bars": 220,
      -      "short_cooldown_bars": 80,
      -      "short_loss_limit": 4,
      -      "short_window_bars": 80
      -    },
      -    "4h": {
      -      "long_cooldown_bars": 96,
      -      "long_loss_limit": 6,
      -      "long_window_bars": 96,
      -      "short_cooldown_bars": 32,
      -      "short_loss_limit": 4,
      -      "short_window_bars": 32
      -    },
      -    "5m": {
      -      "long_cooldown_bars": 480,
      -      "long_loss_limit": 6,
      -      "long_window_bars": 480,
      -      "short_cooldown_bars": 180,
      -      "short_loss_limit": 4,
      -      "short_window_bars": 180
      -    }
      -  },
      -  "description": "Per-timeframe loss-streak cooldown windows (short/long loss limits and cooldown bar counts).",
      -  "properties": {
      -    "15m": {
      -      "additionalProperties": true,
      -      "default": {
      -        "long_cooldown_bars": 320,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 320,
      -        "short_cooldown_bars": 120,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 120
      -      },
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "default": 320,
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "default": 6,
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "default": 320,
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "default": 120,
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "default": 4,
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "default": 120,
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "1d": {
      -      "additionalProperties": true,
      -      "default": {
      -        "long_cooldown_bars": 60,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 60,
      -        "short_cooldown_bars": 20,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 20
      -      },
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "default": 60,
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "default": 6,
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "default": 60,
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "default": 20,
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "default": 4,
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "default": 20,
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "1h": {
      -      "additionalProperties": true,
      -      "default": {
      -        "long_cooldown_bars": 144,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 144,
      -        "short_cooldown_bars": 48,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 48
      -      },
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "default": 144,
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "default": 6,
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "default": 144,
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "default": 48,
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "default": 4,
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "default": 48,
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "30m": {
      -      "additionalProperties": true,
      -      "default": {
      -        "long_cooldown_bars": 220,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 220,
      -        "short_cooldown_bars": 80,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 80
      -      },
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "default": 220,
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "default": 6,
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "default": 220,
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "default": 80,
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "default": 4,
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "default": 80,
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "4h": {
      -      "additionalProperties": true,
      -      "default": {
      -        "long_cooldown_bars": 96,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 96,
      -        "short_cooldown_bars": 32,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 32
      -      },
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "default": 96,
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "default": 6,
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "default": 96,
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "default": 32,
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "default": 4,
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "default": 32,
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "5m": {
      -      "additionalProperties": true,
      -      "default": {
      -        "long_cooldown_bars": 480,
      -        "long_loss_limit": 6,
      -        "long_window_bars": 480,
      -        "short_cooldown_bars": 180,
      -        "short_loss_limit": 4,
      -        "short_window_bars": 180
      -      },
      -      "properties": {
      -        "long_cooldown_bars": {
      -          "default": 480,
      -          "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_loss_limit": {
      -          "default": 6,
      -          "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "long_window_bars": {
      -          "default": 480,
      -          "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_cooldown_bars": {
      -          "default": 180,
      -          "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_loss_limit": {
      -          "default": 4,
      -          "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -          "maximum": 100,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -          "x-mangrove-status": "tunable"
      -        },
      -        "short_window_bars": {
      -          "default": 180,
      -          "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -          "maximum": 10000,
      -          "minimum": 1,
      -          "type": "integer",
      -          "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -          "x-mangrove-status": "tunable"
      -        }
      -      },
      -      "required": [
      -        "short_window_bars",
      -        "long_window_bars",
      -        "short_loss_limit",
      -        "long_loss_limit"
      -      ],
      -      "type": "object"
      -    },
      -    "cadence_reference": {
      -      "description": "Server-selected strategy cadence; metadata rather than a timeframe entry.",
      -      "type": "string"
      -    }
      -  },
      -  "type": [
      -    "object",
      -    "null"
      -  ],
      -  "x-mangrove-effect": "Tighter limits pause trading sooner after a losing streak; looser limits keep trading through drawdowns.",
      -  "x-mangrove-map-value-schema": {
      -    "additionalProperties": true,
      -    "properties": {
      -      "long_cooldown_bars": {
      -        "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "long_loss_limit": {
      -        "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      -        "maximum": 100,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "long_window_bars": {
      -        "description": "Lookback, in bars, over which long_loss_limit is counted.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "short_cooldown_bars": {
      -        "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "short_loss_limit": {
      -        "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      -        "maximum": 100,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      -        "x-mangrove-status": "tunable"
      -      },
      -      "short_window_bars": {
      -        "description": "Lookback, in bars, over which short_loss_limit is counted.",
      -        "maximum": 10000,
      -        "minimum": 1,
      -        "type": "integer",
      -        "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      -        "x-mangrove-status": "tunable"
      -      }
      -    },
      -    "required": [
      -      "short_window_bars",
      -      "long_window_bars",
      -      "short_loss_limit",
      -      "long_loss_limit"
      -    ],
      -    "type": "object"
      -  },
      -  "x-mangrove-status": "tunable"
      -}
    • changedInput schema / properties / constraints / x-mangrove-authoring-schema / properties / cooldown_model / x-mangrove-effect
      Previous value: -"'trades' trips on trade count and loss size regardless of how far apart trades are spaced; 'bars' trips only when losses land inside the window. cooldown_config is ignored under 'trades'."New value: +"'trades' trips on trade count and loss size regardless of how far apart trades are spaced; 'bars' trips only when losses land inside the window. cooldown_config, cooldown_bars, daily_momentum_limit and weekly_momentum_limit are read only under 'bars': they are left out of a resolved config under 'trades', and a config that carries them under 'trades' has them dropped."
    • removedInput schema / properties / constraints / x-mangrove-authoring-schema / properties / daily_momentum_limit
      Removed value: -{
      -  "default": 3,
      -  "description": "Daily momentum-based trade limit.",
      -  "exclusiveMinimum": 0,
      -  "maximum": 100,
      -  "type": [
      -    "number",
      -    "null"
      -  ],
      -  "x-mangrove-effect": "Higher permits more momentum-driven entries per day; lower throttles them.",
      -  "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      -  "x-mangrove-status": "guardrail"
      -}
    • removedInput schema / properties / constraints / x-mangrove-authoring-schema / properties / weekly_momentum_limit
      Removed value: -{
      -  "default": 3,
      -  "description": "Weekly momentum-based trade limit.",
      -  "exclusiveMinimum": 0,
      -  "maximum": 100,
      -  "type": [
      -    "number",
      -    "null"
      -  ],
      -  "x-mangrove-effect": "Higher permits more momentum-driven entries per week; lower throttles them.",
      -  "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      -  "x-mangrove-status": "guardrail"
      -}
  4. Changed3 schema fields changed
    • addedInput schema / properties / constraints / additionalProperties
      Added value: +true
    • addedInput schema / properties / constraints / properties
      Added value: +{
      +  "atr_cap_multiplier": {
      +    "description": "SUPERSEDED by volatility_tolerance. Bounded the weighted blend at this multiple of the SHORT ATR.",
      +    "x-mangrove-authoring-schema": {
      +      "description": "SUPERSEDED by volatility_tolerance. Bounded the weighted blend at this multiple of the SHORT ATR.",
      +      "minimum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. On a weighted_atr strategy this is what made the weight pair inert past a long weight of roughly 6-12% (#1052).",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    }
      +  },
      +  "atr_long_weight": {
      +    "description": "SUPERSEDED by volatility_tolerance. Weight of the daily ATR in the weighted-blend stop model, and always 1 - atr_short_weight rather than independent.",
      +    "x-mangrove-authoring-schema": {
      +      "description": "SUPERSEDED by volatility_tolerance. Weight of the daily ATR in the weighted-blend stop model, and always 1 - atr_short_weight rather than independent.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. Derived, never independently effective.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    }
      +  },
      +  "atr_period": {
      +    "description": "ATR lookback in bars (default 14) used to measure volatility for stop sizing.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 14,
      +      "description": "ATR lookback in bars (default 14) used to measure volatility for stop sizing.",
      +      "maximum": 1000,
      +      "minimum": 5,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher smooths the volatility estimate (steadier, slower-reacting stops). Lower reacts faster to recent volatility (choppier stops).",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "atr_short_weight": {
      +    "description": "SUPERSEDED by volatility_tolerance. Weight of the signal-timeframe ATR in the weighted-blend stop model. Readable on a strategy created under that model; refused on any write.",
      +    "x-mangrove-authoring-schema": {
      +      "description": "SUPERSEDED by volatility_tolerance. Weight of the signal-timeframe ATR in the weighted-blend stop model. Readable on a strategy created under that model; refused on any write.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. On a weighted_atr strategy, higher favours the signal timeframe's own volatility -- though the cap made settings past a few percent of long weight indistinguishable (#1052).",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    }
      +  },
      +  "atr_volatility_factor": {
      +    "description": "SUPERSEDED by volatility_tolerance. Multiplied the blended ATR to give the stop distance. The dial's two endpoint factors carry this instead, one at each end of the width.",
      +    "x-mangrove-authoring-schema": {
      +      "description": "SUPERSEDED by volatility_tolerance. Multiplied the blended ATR to give the stop distance. The dial's two endpoint factors carry this instead, one at each end of the width.",
      +      "exclusiveMinimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. On a weighted_atr strategy, higher widens the stop and shrinks the position for the same risk.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    }
      +  },
      +  "circuit_breaker": {
      +    "description": "Parameters for cooldown_model 'trades': pause on consecutive net losses or accumulated loss amount, pause on marked drawdown from the peak (including unrealized changes), resume new alpha positions at a reduced size, and stop after consecutive pauses. Canon defaults are 36 primary bars for a loss pause, 72 for a drawdown pause, and three strikes for a permanent halt. Pause counts are clamped to 24 hours through 14 days by default. max_drawdown_halt_limit separately stops entries on realized loss of cumulative gross deposits. Existing exits remain active during holds.",
      +    "x-mangrove-authoring-schema": {
      +      "additionalProperties": false,
      +      "default": {
      +        "consecutive_loss_limit": 4,
      +        "drawdown_pause_bars": 72,
      +        "loss_amount_pct": 0.06,
      +        "max_consecutive_pauses": 3,
      +        "pause_bars": 36,
      +        "pause_max_days": 14,
      +        "pause_min_hours": 24,
      +        "resume_size_fraction": 0.5,
      +        "resume_trades": 3
      +      },
      +      "description": "Parameters for cooldown_model 'trades': pause on consecutive net losses or accumulated loss amount, pause on marked drawdown from the peak (including unrealized changes), resume new alpha positions at a reduced size, and stop after consecutive pauses. Canon defaults are 36 primary bars for a loss pause, 72 for a drawdown pause, and three strikes for a permanent halt. Pause counts are clamped to 24 hours through 14 days by default. max_drawdown_halt_limit separately stops entries on realized loss of cumulative gross deposits. Existing exits remain active during holds.",
      +      "properties": {
      +        "consecutive_loss_limit": {
      +          "default": 4,
      +          "description": "Consecutive losing closes on an asset that start a pause. A winning close resets the count.",
      +          "maximum": 100,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Lower pauses sooner after a losing run; higher tolerates longer runs.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "drawdown_pause_bars": {
      +          "default": 72,
      +          "description": "Primary-timeframe bars denying entries after a drawdown pause (canon default 72). At drawdown-pause expiry the peak re-baselines to current account value. An alpha resume window opens only once no pause remains and no permanent halt is latched. The count is raised to cover pause_min_hours and lowered to fit pause_max_days (24 hours through 14 days by default).",
      +          "maximum": 8760,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Longer holds the pause longer before trading can resume.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "loss_amount_pct": {
      +          "default": 0.06,
      +          "description": "Accumulated net losses as a fraction of the closed-equity reset baseline that start a loss pause. A winning close clears the accumulation and resets the baseline. An asset loss pause clears it at the start and re-baselines at expiry; a global drawdown pause does not itself reset it.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 1,
      +          "type": "number",
      +          "x-mangrove-effect": "Lower pauses after smaller cumulative losses; higher tolerates larger ones.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "max_consecutive_pauses": {
      +          "default": 3,
      +          "description": "Strikes that stop the strategy until a manual restart. A strike is one pause started, of any kind (consecutive losses, loss amount, drawdown, a resume window that lost money). Strikes reset to 0 only on a new equity high: a close that leaves closed equity above the high-water mark the strategy had when the first strike of the run was recorded. A winning close below that mark does not reset them, and a deposit or withdrawal does not count as a high.",
      +          "maximum": 100,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Lower stops the strategy sooner; higher tolerates more repeated pauses.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "pause_bars": {
      +          "default": 36,
      +          "description": "Primary-timeframe bars denying entries after a loss pause (canon default 36). The count is raised to cover pause_min_hours and lowered to fit pause_max_days on that timeframe (24 hours through 14 days by default).",
      +          "maximum": 8760,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Longer sits out more of a bad regime; shorter resumes sooner.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "pause_max_days": {
      +          "default": 14,
      +          "description": "A pause lasts at most this many days on every timeframe: the bar count is lowered to fit it.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 365,
      +          "type": "number",
      +          "x-mangrove-effect": "Lower ends every pause sooner on long timeframes; higher leaves the bar count to decide.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "pause_min_hours": {
      +          "default": 24,
      +          "description": "A pause lasts at least this many hours on every timeframe: the bar count of pause_bars or drawdown_pause_bars is raised to cover it.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 336,
      +          "type": "number",
      +          "x-mangrove-effect": "Higher makes every pause at least that long on short timeframes; lower leaves the bar count to decide.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "resume_size_fraction": {
      +          "default": 0.5,
      +          "description": "Fraction of normal size for new alpha positions while a resume window is open (canon default 0.5). Eligible confirmed position closes count toward resume_trades; a negative net result starts another loss pause and strike, while zero or a profit restores full alpha size. Core orders keep their normal allocation quantities after pause expiry: they are not positions and do not consume resume-trade counts. 1.0 disables the alpha size reduction.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 1,
      +          "type": "number",
      +          "x-mangrove-effect": "Lower risks less while the strategy proves itself again after a pause; higher resumes closer to full size.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "resume_trades": {
      +          "default": 3,
      +          "description": "Eligible confirmed position closes booked in a resume window (canon default three). When the window completes, a negative net realized result starts a new loss pause and strike; zero or a profit restores full alpha size. A pause cancels the active window; a new one opens only once no pause remains and no permanent halt is latched. Core orders do not count as position closes.",
      +          "maximum": 50,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Higher judges the resumed strategy over more trades before full size returns; lower decides sooner.",
      +          "x-mangrove-status": "tunable"
      +        }
      +      },
      +      "type": [
      +        "object",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Tighter limits pause and stop sooner; looser limits keep trading through losing runs.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "cooldown_bars": {
      +    "description": "Bars to wait between trades on the same asset.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 24,
      +      "description": "Bars to wait between trades on the same asset.",
      +      "maximum": 10000,
      +      "minimum": 0,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher spaces trades out (reduces overtrading and whipsaw); lower allows quicker re-entry.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "cooldown_config": {
      +    "description": "Per-timeframe loss-streak cooldown windows (short/long loss limits and cooldown bar counts).",
      +    "x-mangrove-authoring-schema": {
      +      "additionalProperties": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "long_cooldown_bars": {
      +            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_loss_limit": {
      +            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_window_bars": {
      +            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_cooldown_bars": {
      +            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_loss_limit": {
      +            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_window_bars": {
      +            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +            "x-mangrove-status": "tunable"
      +          }
      +        },
      +        "required": [
      +          "short_window_bars",
      +          "long_window_bars",
      +          "short_loss_limit",
      +          "long_loss_limit"
      +        ],
      +        "type": "object"
      +      },
      +      "default": {
      +        "15m": {
      +          "long_cooldown_bars": 320,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 320,
      +          "short_cooldown_bars": 120,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 120
      +        },
      +        "1d": {
      +          "long_cooldown_bars": 60,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 60,
      +          "short_cooldown_bars": 20,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 20
      +        },
      +        "1h": {
      +          "long_cooldown_bars": 144,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 144,
      +          "short_cooldown_bars": 48,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 48
      +        },
      +        "30m": {
      +          "long_cooldown_bars": 220,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 220,
      +          "short_cooldown_bars": 80,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 80
      +        },
      +        "4h": {
      +          "long_cooldown_bars": 96,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 96,
      +          "short_cooldown_bars": 32,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 32
      +        },
      +        "5m": {
      +          "long_cooldown_bars": 480,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 480,
      +          "short_cooldown_bars": 180,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 180
      +        }
      +      },
      +      "description": "Per-timeframe loss-streak cooldown windows (short/long loss limits and cooldown bar counts).",
      +      "properties": {
      +        "15m": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 320,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 320,
      +            "short_cooldown_bars": 120,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 120
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 320,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 320,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 120,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 120,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "1d": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 60,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 60,
      +            "short_cooldown_bars": 20,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 20
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 60,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 60,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 20,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 20,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "1h": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 144,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 144,
      +            "short_cooldown_bars": 48,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 48
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 144,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 144,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 48,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 48,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "30m": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 220,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 220,
      +            "short_cooldown_bars": 80,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 80
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 220,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 220,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 80,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 80,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "4h": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 96,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 96,
      +            "short_cooldown_bars": 32,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 32
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 96,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 96,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 32,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 32,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "5m": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 480,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 480,
      +            "short_cooldown_bars": 180,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 180
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 480,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 480,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 180,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 180,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "cadence_reference": {
      +          "description": "Server-selected strategy cadence; metadata rather than a timeframe entry.",
      +          "type": "string"
      +        }
      +      },
      +      "type": [
      +        "object",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Tighter limits pause trading sooner after a losing streak; looser limits keep trading through drawdowns.",
      +      "x-mangrove-map-value-schema": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "long_cooldown_bars": {
      +            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_loss_limit": {
      +            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_window_bars": {
      +            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_cooldown_bars": {
      +            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_loss_limit": {
      +            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_window_bars": {
      +            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +            "x-mangrove-status": "tunable"
      +          }
      +        },
      +        "required": [
      +          "short_window_bars",
      +          "long_window_bars",
      +          "short_loss_limit",
      +          "long_loss_limit"
      +        ],
      +        "type": "object"
      +      },
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "cooldown_model": {
      +    "description": "Loss-streak breaker model. 'bars' counts losing closes inside rolling windows of the primary timeframe (cooldown_config). 'trades' counts consecutive losing closes and realized loss amount, pauses for circuit_breaker bars of the primary timeframe (at least pause_min_hours and at most pause_max_days), and stops after repeated pauses (circuit_breaker). An absent model adopts the canonical 'trades' defaults; explicit 'bars' retains the legacy model.",
      +    "x-mangrove-authoring-schema": {
      +      "default": "trades",
      +      "description": "Loss-streak breaker model. 'bars' counts losing closes inside rolling windows of the primary timeframe (cooldown_config). 'trades' counts consecutive losing closes and realized loss amount, pauses for circuit_breaker bars of the primary timeframe (at least pause_min_hours and at most pause_max_days), and stops after repeated pauses (circuit_breaker). An absent model adopts the canonical 'trades' defaults; explicit 'bars' retains the legacy model.",
      +      "enum": [
      +        "bars",
      +        "trades",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "'trades' trips on trade count and loss size regardless of how far apart trades are spaced; 'bars' trips only when losses land inside the window. cooldown_config is ignored under 'trades'.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "daily_momentum_limit": {
      +    "description": "Daily momentum-based trade limit.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 3,
      +      "description": "Daily momentum-based trade limit.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 100,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher permits more momentum-driven entries per day; lower throttles them.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "enable_volatility_adjustment": {
      +    "description": "Toggles volatility-based position scaling (default false).",
      +    "x-mangrove-authoring-schema": {
      +      "default": false,
      +      "description": "Toggles volatility-based position scaling (default false).",
      +      "type": [
      +        "boolean",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "When true, positions are scaled down by target_volatility / (atr/entry) if ATR%% exceeds target; only reduces size, never increases.",
      +      "x-mangrove-status": "gated"
      +    }
      +  },
      +  "exit_on_loss_after_bars": {
      +    "description": "Exit a losing position after this many bars.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 1000,
      +      "description": "Exit a losing position after this many bars.",
      +      "maximum": 10000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower cuts losers sooner; higher gives them more time to recover.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "exit_on_profit_after_bars": {
      +    "description": "Exit a winning position after this many bars.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 1000,
      +      "description": "Exit a winning position after this many bars.",
      +      "maximum": 10000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower banks winners sooner; higher lets them run.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "initial_balance": {
      +    "description": "Starting balance for the backtest/simulation (default $10,000).",
      +    "x-mangrove-authoring-schema": {
      +      "default": 10000,
      +      "description": "Starting balance for the backtest/simulation (default $10,000).",
      +      "maximum": 1000000000,
      +      "minimum": 25,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Scales absolute dollar figures; not a strategy-character knob.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "max_drawdown_halt_limit": {
      +    "description": "Permanent capital-floor entry halt (0.20 = 20%). Closed, realized equity is compared with cumulative gross deposits (execution_state.cumulative_deposits), not a rolling peak or the signed net-funding balance; withdrawals do not reduce this reference. Legacy requests without cumulative_deposits use execution_config.initial_balance. The shared live/paper evaluator checks before each bar and latches execution_state.halt. New alpha entries and v3 core allocations are denied, while authoritative positions retain protective exits and exits_pending until physically flat. Engine-owned strategies become inactive only after that book is flat; caller-owned executors retain their exit monitor. An explicit manual restart is required to clear the latch. Backtests enforce the same floor when evaluate_bar receives enforce_capital_floor=True, managing open-position exits through the final bar. Applies to both cooldown models; null disables new floor trips, while an existing halt remains latched.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.2,
      +      "description": "Permanent capital-floor entry halt (0.20 = 20%). Closed, realized equity is compared with cumulative gross deposits (execution_state.cumulative_deposits), not a rolling peak or the signed net-funding balance; withdrawals do not reduce this reference. Legacy requests without cumulative_deposits use execution_config.initial_balance. The shared live/paper evaluator checks before each bar and latches execution_state.halt. New alpha entries and v3 core allocations are denied, while authoritative positions retain protective exits and exits_pending until physically flat. Engine-owned strategies become inactive only after that book is flat; caller-owned executors retain their exit monitor. An explicit manual restart is required to clear the latch. Backtests enforce the same floor when evaluate_bar receives enforce_capital_floor=True, managing open-position exits through the final bar. Applies to both cooldown models; null disables new floor trips, while an existing halt remains latched.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower protects more of gross deposited capital before a permanent entry halt; higher tolerates a deeper realized loss. This does not resize positions or stop protective exit evaluation. Do not add a separate floor where the shared evaluator enforces it.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "max_drawdown_limit": {
      +    "description": "Peak-relative entry pause (0.20 = 20%). The canonical 'trades' model measures marked equity against its high-water mark. A breach starts one drawdown pause and strike; circuit_breaker.drawdown_pause_bars defaults to 72 primary bars, clamped to pause_min_hours and pause_max_days (24 hours and 14 days by default). At drawdown-pause expiry the peak re-baselines; a reduced-size alpha resume window opens only once no pause remains and no permanent halt is latched. Explicit 'bars' retains the legacy closed-equity measurement and per-timeframe long cooldown. Both models deny new entries while allowing existing positions to exit; automatic v3 core allocations honor the hold too. null disables new drawdown trips.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.2,
      +      "description": "Peak-relative entry pause (0.20 = 20%). The canonical 'trades' model measures marked equity against its high-water mark. A breach starts one drawdown pause and strike; circuit_breaker.drawdown_pause_bars defaults to 72 primary bars, clamped to pause_min_hours and pause_max_days (24 hours and 14 days by default). At drawdown-pause expiry the peak re-baselines; a reduced-size alpha resume window opens only once no pause remains and no permanent halt is latched. Explicit 'bars' retains the legacy closed-equity measurement and per-timeframe long cooldown. Both models deny new entries while allowing existing positions to exit; automatic v3 core allocations honor the hold too. null disables new drawdown trips.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower pauses entries after a smaller drawdown; higher tolerates a deeper drawdown. The shared entry breaker enforces this in single/bulk live and paper evaluation, v3 core allocation and backtests built with risk_manager_from_execution_config. Alpha resume sizing is a separate control; do not add a second drawdown stop.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "max_hold_bars": {
      +    "description": "Maximum bars to hold any position before a forced exit.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 1000,
      +      "description": "Maximum bars to hold any position before a forced exit.",
      +      "maximum": 10000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher lets trades run longer; lower forces earlier time-based exits.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "max_hold_time_hours": {
      +    "description": "Maximum position hold time in hours (null = no limit).",
      +    "x-mangrove-authoring-schema": {
      +      "default": null,
      +      "description": "Maximum position hold time in hours (null = no limit).",
      +      "exclusiveMinimum": 1,
      +      "maximum": 8760,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower forces earlier time-based exits; null/higher lets trades run indefinitely on time.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "max_open_positions": {
      +    "description": "Maximum concurrent open positions.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 10,
      +      "description": "Maximum concurrent open positions.",
      +      "maximum": 1000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher allows more simultaneous exposure (more diversification but more aggregate risk); lower is more selective with less aggregate exposure.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "max_risk_per_trade": {
      +    "description": "Fraction of account equity risked per trade (0.01 = 1%). Position size is derived from this and the stop distance.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.01,
      +      "description": "Fraction of account equity risked per trade (0.01 = 1%). Position size is derived from this and the stop distance.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher risks more per trade: bigger positions, larger gains AND larger drawdowns. Lower is more conservative: smaller positions, smaller swings.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "max_trade_amount": {
      +    "description": "Absolute cap on dollar size per trade.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 10000000,
      +      "description": "Absolute cap on dollar size per trade.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1000000000000,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Size guardrail; rarely binding.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "max_trades_per_day": {
      +    "description": "Daily trade cap.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 50,
      +      "description": "Daily trade cap.",
      +      "maximum": 1440,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher permits more churn; lower throttles activity.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "max_units_per_trade": {
      +    "description": "Absolute cap on units per trade.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 1000000,
      +      "description": "Absolute cap on units per trade.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1000000000000,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Size guardrail; rarely binding.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "min_asset_balance": {
      +    "description": "position_size_calc 'v3' only. Minimum asset balance, in asset units, the strategy holds outside open trades.",
      +    "x-mangrove-authoring-schema": {
      +      "description": "position_size_calc 'v3' only. Minimum asset balance, in asset units, the strategy holds outside open trades.",
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher keeps more of the asset out of reach of sell trades and core sells, and takes more cash to reach; lower frees more of the asset for trading.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "min_balance_days": {
      +    "description": "position_size_calc 'v3' only. Number of equal daily orders used to bring a side up to its minimum balance.",
      +    "x-mangrove-authoring-schema": {
      +      "description": "position_size_calc 'v3' only. Number of equal daily orders used to bring a side up to its minimum balance.",
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher spreads the minimum-balance orders over more days at smaller size; lower reaches the minimum sooner with larger orders.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "min_balance_threshold": {
      +    "description": "Cash reserve fraction held back from new entries (0.1 = 10%). v1 reserves this fraction of cash; v2 reserves this fraction of account value (cash + open positions at market). An entry may only use cash above the reserve; when no cash is deployable the entry is denied (insufficient_cash / insufficient_cash_v2_account_reserve). It never halts the strategy and never closes positions.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.1,
      +      "description": "Cash reserve fraction held back from new entries (0.1 = 10%). v1 reserves this fraction of cash; v2 reserves this fraction of account value (cash + open positions at market). An entry may only use cash above the reserve; when no cash is deployable the entry is denied (insufficient_cash / insufficient_cash_v2_account_reserve). It never halts the strategy and never closes positions.",
      +      "exclusiveMaximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher keeps more cash idle and makes entries smaller or rarer as the account shrinks; lower lets entries use more of the balance. Not a drawdown stop; see max_drawdown_limit and max_drawdown_halt_limit.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "min_cash_balance": {
      +    "description": "position_size_calc 'v3' only. Minimum cash balance the strategy holds after the worst-case loss of every open trade.",
      +    "x-mangrove-authoring-schema": {
      +      "description": "position_size_calc 'v3' only. Minimum cash balance the strategy holds after the worst-case loss of every open trade.",
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher keeps more cash out of reach of buy trades and core buys, so entries are smaller or rarer; lower frees more cash for trading.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "min_stop_distance_pct": {
      +    "description": "Hard floor on stop distance as a fraction of entry price (crypto minimum), applied after ATR sizing.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.005,
      +      "description": "Hard floor on stop distance as a fraction of entry price (crypto minimum), applied after ATR sizing.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher enforces a wider minimum stop; lower allows tighter stops down to the floor.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "min_trade_amount": {
      +    "description": "Minimum trade size in dollars; smaller intended trades are skipped.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 25,
      +      "description": "Minimum trade size in dollars; smaller intended trades are skipped.",
      +      "maximum": 1000000,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher skips more small signals; lower allows smaller trades.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "position_size_calc": {
      +    "description": "Sizing-engine version ('v1', 'v2' or 'v3'). Pinned at creation and immutable. 'v3' holds an asset balance and a cash balance, sizes against equity net of open risk, and requires the position_size_calc 'v3' parameters.",
      +    "x-mangrove-authoring-schema": {
      +      "default": "v2",
      +      "description": "Sizing-engine version ('v1', 'v2' or 'v3'). Pinned at creation and immutable. 'v3' holds an asset balance and a cash balance, sizes against equity net of open risk, and requires the position_size_calc 'v3' parameters.",
      +      "enum": [
      +        "v1",
      +        "v2",
      +        "v3",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Not a magnitude knob; selects the sizing algorithm. Do not change on an existing strategy.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "profit_threshold_pct": {
      +    "description": "Profit threshold (5%% default) above which a position counts as 'winning' for the time-based exit logic.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.05,
      +      "description": "Profit threshold (5%% default) above which a position counts as 'winning' for the time-based exit logic.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher requires a larger gain before a position is treated as winning; lower treats smaller gains as wins.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "rebalance_band": {
      +    "description": "position_size_calc 'v3' only. Absolute deviation of the asset weight from target_asset_weight that triggers a rebalance order (0.05 = 5 points).",
      +    "x-mangrove-authoring-schema": {
      +      "description": "position_size_calc 'v3' only. Absolute deviation of the asset weight from target_asset_weight that triggers a rebalance order (0.05 = 5 points).",
      +      "exclusiveMaximum": 1,
      +      "exclusiveMinimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher lets the split drift further before a rebalance order, so fewer core orders; lower holds the split closer to target with more core orders and more fees.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "reward_factor": {
      +    "description": "Risk/reward target. Take-profit distance = reward_factor * stop_distance.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 2,
      +      "description": "Risk/reward target. Take-profit distance = reward_factor * stop_distance.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 100,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher sets a wider profit target: lower win rate but bigger wins. Lower sets a tighter target: higher win rate but smaller wins.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "stop_gap_allowance": {
      +    "description": "position_size_calc 'v3' only. Fraction of the stop price a stop fill is assumed to miss by when computing the worst-case loss of a trade (0.01 = 1%).",
      +    "x-mangrove-authoring-schema": {
      +      "description": "position_size_calc 'v3' only. Fraction of the stop price a stop fill is assumed to miss by when computing the worst-case loss of a trade (0.01 = 1%).",
      +      "exclusiveMaximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher counts more risk per open trade, leaving less available cash and smaller positions; lower counts less.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "stop_model": {
      +    "description": "Which stop model the strategy uses: 'atr_width_dial' (one parameter, volatility_tolerance, positioned on the ATR width) or 'weighted_atr' (superseded: a weighted blend of two ATRs, capped). Pinned at creation and immutable.",
      +    "x-mangrove-authoring-schema": {
      +      "default": "atr_width_dial",
      +      "description": "Which stop model the strategy uses: 'atr_width_dial' (one parameter, volatility_tolerance, positioned on the ATR width) or 'weighted_atr' (superseded: a weighted blend of two ATRs, capped). Pinned at creation and immutable.",
      +      "enum": [
      +        "atr_width_dial",
      +        "weighted_atr",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Not a magnitude knob; selects the stop algorithm. Do not change on an existing strategy -- it would move every stop the strategy takes.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "taker_fee_rate": {
      +    "description": "position_size_calc 'v3' only. Venue fee per fill as a fraction of notional, charged in cash (0.004 = 0.4%).",
      +    "x-mangrove-authoring-schema": {
      +      "description": "position_size_calc 'v3' only. Venue fee per fill as a fraction of notional, charged in cash (0.004 = 0.4%).",
      +      "exclusiveMaximum": 0.1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher counts more cost per fill, raising the risk of each trade and lowering available cash. Models the venue; not a strategy-character knob.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "target_asset_weight": {
      +    "description": "position_size_calc 'v3' only. Target share of core value held in the asset (0.8 = 80% asset, 20% cash; 0 = all cash).",
      +    "x-mangrove-authoring-schema": {
      +      "description": "position_size_calc 'v3' only. Target share of core value held in the asset (0.8 = 80% asset, 20% cash; 0 = all cash).",
      +      "exclusiveMaximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher holds more of the asset and less cash; lower holds more cash. The daily core order moves the split back to this value once it drifts past rebalance_band. At 0 with no asset held, no core order is placed and only buy trades can pass.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "target_volatility": {
      +    "description": "Target volatility (0.10 = 10%). ONLY active when enable_volatility_adjustment is true (default false). When active, scales position size down if ATR%% of entry exceeds the target (never up).",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.1,
      +      "description": "Target volatility (0.10 = 10%). ONLY active when enable_volatility_adjustment is true (default false). When active, scales position size down if ATR%% of entry exceeds the target (never up).",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "With the gate off (the default), changing this has no effect. With it on, lower scales positions down more aggressively in high volatility.",
      +      "x-mangrove-gate-field": "enable_volatility_adjustment",
      +      "x-mangrove-gate-required": true,
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "gated"
      +    }
      +  },
      +  "volatility_mode": {
      +    "description": "Unused (retained for backward compatibility). Volatility is derived from ATR.",
      +    "x-mangrove-authoring-schema": {
      +      "default": "stddev",
      +      "description": "Unused (retained for backward compatibility). Volatility is derived from ATR.",
      +      "enum": [
      +        "stddev",
      +        "atr",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "No runtime effect. Do not tune.",
      +      "x-mangrove-status": "unused"
      +    }
      +  },
      +  "volatility_tolerance": {
      +    "description": "Where on the ATR width the stop is taken, as the ATR_long-vs-ATR_short contribution ratio: 0 is all short end (0.5x the signal timeframe's ATR), 1 is all long end (2x the daily ATR). Interpolated geometrically, so the value is exactly the long end's share of log(stop) and each 0.1 is the same multiplicative step. Replaces atr_short_weight, atr_long_weight and atr_cap_multiplier.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 0.5,
      +      "description": "Where on the ATR width the stop is taken, as the ATR_long-vs-ATR_short contribution ratio: 0 is all short end (0.5x the signal timeframe's ATR), 1 is all long end (2x the daily ATR). Interpolated geometrically, so the value is exactly the long end's share of log(stop) and each 0.1 is the same multiplicative step. Replaces atr_short_weight, atr_long_weight and atr_cap_multiplier.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher widens the stop, and because position size is the risk budget divided by the stop distance, exposure shrinks in exact inverse proportion at the SAME risk. Low means many units with little room to be wrong and frequent stop-outs; high means few units that are hard to shake out but need a much larger move to reach the same reward. Both risk max_risk_per_trade.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    }
      +  },
      +  "volatility_window": {
      +    "description": "Unused (retained for backward compatibility). ATR windowing is controlled by atr_period.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 24,
      +      "description": "Unused (retained for backward compatibility). ATR windowing is controlled by atr_period.",
      +      "maximum": 1000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "No runtime effect. Do not tune.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "unused"
      +    }
      +  },
      +  "weekly_momentum_limit": {
      +    "description": "Weekly momentum-based trade limit.",
      +    "x-mangrove-authoring-schema": {
      +      "default": 3,
      +      "description": "Weekly momentum-based trade limit.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 100,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher permits more momentum-driven entries per week; lower throttles them.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  }
      +}
    • addedInput schema / properties / constraints / x-mangrove-authoring-schema
      Added value: +{
      +  "$id": "urn:mangrove:execution-config:1",
      +  "$schema": "https://json-schema.org/draft/2020-12/schema",
      +  "additionalProperties": true,
      +  "description": "Canonical authoring representation derived from server metadata and defaults. Top-level optional keys may be omitted or null. The existing HTTP validator separately coerces top-level numeric strings, enforces their declared bounds and permits unknown/legacy fields; it does not enforce this whole nested schema. Runtime strategy/version/timeframe checks remain authoritative. Cooldown durations may be omitted by legacy configs and then fall back to their corresponding windows.",
      +  "properties": {
      +    "atr_cap_multiplier": {
      +      "description": "SUPERSEDED by volatility_tolerance. Bounded the weighted blend at this multiple of the SHORT ATR.",
      +      "minimum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. On a weighted_atr strategy this is what made the weight pair inert past a long weight of roughly 6-12% (#1052).",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    },
      +    "atr_long_weight": {
      +      "description": "SUPERSEDED by volatility_tolerance. Weight of the daily ATR in the weighted-blend stop model, and always 1 - atr_short_weight rather than independent.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. Derived, never independently effective.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    },
      +    "atr_period": {
      +      "default": 14,
      +      "description": "ATR lookback in bars (default 14) used to measure volatility for stop sizing.",
      +      "maximum": 1000,
      +      "minimum": 5,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher smooths the volatility estimate (steadier, slower-reacting stops). Lower reacts faster to recent volatility (choppier stops).",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "atr_short_weight": {
      +      "description": "SUPERSEDED by volatility_tolerance. Weight of the signal-timeframe ATR in the weighted-blend stop model. Readable on a strategy created under that model; refused on any write.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. On a weighted_atr strategy, higher favours the signal timeframe's own volatility -- though the cap made settings past a few percent of long weight indistinguishable (#1052).",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    },
      +    "atr_volatility_factor": {
      +      "description": "SUPERSEDED by volatility_tolerance. Multiplied the blended ATR to give the stop distance. The dial's two endpoint factors carry this instead, one at each end of the width.",
      +      "exclusiveMinimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "None on a strategy using atr_width_dial. On a weighted_atr strategy, higher widens the stop and shrinks the position for the same risk.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "superseded",
      +      "x-mangrove-superseded-by": "volatility_tolerance"
      +    },
      +    "circuit_breaker": {
      +      "additionalProperties": false,
      +      "default": {
      +        "consecutive_loss_limit": 4,
      +        "drawdown_pause_bars": 72,
      +        "loss_amount_pct": 0.06,
      +        "max_consecutive_pauses": 3,
      +        "pause_bars": 36,
      +        "pause_max_days": 14,
      +        "pause_min_hours": 24,
      +        "resume_size_fraction": 0.5,
      +        "resume_trades": 3
      +      },
      +      "description": "Parameters for cooldown_model 'trades': pause on consecutive net losses or accumulated loss amount, pause on marked drawdown from the peak (including unrealized changes), resume new alpha positions at a reduced size, and stop after consecutive pauses. Canon defaults are 36 primary bars for a loss pause, 72 for a drawdown pause, and three strikes for a permanent halt. Pause counts are clamped to 24 hours through 14 days by default. max_drawdown_halt_limit separately stops entries on realized loss of cumulative gross deposits. Existing exits remain active during holds.",
      +      "properties": {
      +        "consecutive_loss_limit": {
      +          "default": 4,
      +          "description": "Consecutive losing closes on an asset that start a pause. A winning close resets the count.",
      +          "maximum": 100,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Lower pauses sooner after a losing run; higher tolerates longer runs.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "drawdown_pause_bars": {
      +          "default": 72,
      +          "description": "Primary-timeframe bars denying entries after a drawdown pause (canon default 72). At drawdown-pause expiry the peak re-baselines to current account value. An alpha resume window opens only once no pause remains and no permanent halt is latched. The count is raised to cover pause_min_hours and lowered to fit pause_max_days (24 hours through 14 days by default).",
      +          "maximum": 8760,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Longer holds the pause longer before trading can resume.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "loss_amount_pct": {
      +          "default": 0.06,
      +          "description": "Accumulated net losses as a fraction of the closed-equity reset baseline that start a loss pause. A winning close clears the accumulation and resets the baseline. An asset loss pause clears it at the start and re-baselines at expiry; a global drawdown pause does not itself reset it.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 1,
      +          "type": "number",
      +          "x-mangrove-effect": "Lower pauses after smaller cumulative losses; higher tolerates larger ones.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "max_consecutive_pauses": {
      +          "default": 3,
      +          "description": "Strikes that stop the strategy until a manual restart. A strike is one pause started, of any kind (consecutive losses, loss amount, drawdown, a resume window that lost money). Strikes reset to 0 only on a new equity high: a close that leaves closed equity above the high-water mark the strategy had when the first strike of the run was recorded. A winning close below that mark does not reset them, and a deposit or withdrawal does not count as a high.",
      +          "maximum": 100,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Lower stops the strategy sooner; higher tolerates more repeated pauses.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "pause_bars": {
      +          "default": 36,
      +          "description": "Primary-timeframe bars denying entries after a loss pause (canon default 36). The count is raised to cover pause_min_hours and lowered to fit pause_max_days on that timeframe (24 hours through 14 days by default).",
      +          "maximum": 8760,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Longer sits out more of a bad regime; shorter resumes sooner.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "pause_max_days": {
      +          "default": 14,
      +          "description": "A pause lasts at most this many days on every timeframe: the bar count is lowered to fit it.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 365,
      +          "type": "number",
      +          "x-mangrove-effect": "Lower ends every pause sooner on long timeframes; higher leaves the bar count to decide.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "pause_min_hours": {
      +          "default": 24,
      +          "description": "A pause lasts at least this many hours on every timeframe: the bar count of pause_bars or drawdown_pause_bars is raised to cover it.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 336,
      +          "type": "number",
      +          "x-mangrove-effect": "Higher makes every pause at least that long on short timeframes; lower leaves the bar count to decide.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "resume_size_fraction": {
      +          "default": 0.5,
      +          "description": "Fraction of normal size for new alpha positions while a resume window is open (canon default 0.5). Eligible confirmed position closes count toward resume_trades; a negative net result starts another loss pause and strike, while zero or a profit restores full alpha size. Core orders keep their normal allocation quantities after pause expiry: they are not positions and do not consume resume-trade counts. 1.0 disables the alpha size reduction.",
      +          "exclusiveMinimum": 0,
      +          "maximum": 1,
      +          "type": "number",
      +          "x-mangrove-effect": "Lower risks less while the strategy proves itself again after a pause; higher resumes closer to full size.",
      +          "x-mangrove-status": "tunable"
      +        },
      +        "resume_trades": {
      +          "default": 3,
      +          "description": "Eligible confirmed position closes booked in a resume window (canon default three). When the window completes, a negative net realized result starts a new loss pause and strike; zero or a profit restores full alpha size. A pause cancels the active window; a new one opens only once no pause remains and no permanent halt is latched. Core orders do not count as position closes.",
      +          "maximum": 50,
      +          "minimum": 1,
      +          "type": "integer",
      +          "x-mangrove-effect": "Higher judges the resumed strategy over more trades before full size returns; lower decides sooner.",
      +          "x-mangrove-status": "tunable"
      +        }
      +      },
      +      "type": [
      +        "object",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Tighter limits pause and stop sooner; looser limits keep trading through losing runs.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "cooldown_bars": {
      +      "default": 24,
      +      "description": "Bars to wait between trades on the same asset.",
      +      "maximum": 10000,
      +      "minimum": 0,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher spaces trades out (reduces overtrading and whipsaw); lower allows quicker re-entry.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "cooldown_config": {
      +      "additionalProperties": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "long_cooldown_bars": {
      +            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_loss_limit": {
      +            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_window_bars": {
      +            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_cooldown_bars": {
      +            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_loss_limit": {
      +            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_window_bars": {
      +            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +            "x-mangrove-status": "tunable"
      +          }
      +        },
      +        "required": [
      +          "short_window_bars",
      +          "long_window_bars",
      +          "short_loss_limit",
      +          "long_loss_limit"
      +        ],
      +        "type": "object"
      +      },
      +      "default": {
      +        "15m": {
      +          "long_cooldown_bars": 320,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 320,
      +          "short_cooldown_bars": 120,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 120
      +        },
      +        "1d": {
      +          "long_cooldown_bars": 60,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 60,
      +          "short_cooldown_bars": 20,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 20
      +        },
      +        "1h": {
      +          "long_cooldown_bars": 144,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 144,
      +          "short_cooldown_bars": 48,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 48
      +        },
      +        "30m": {
      +          "long_cooldown_bars": 220,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 220,
      +          "short_cooldown_bars": 80,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 80
      +        },
      +        "4h": {
      +          "long_cooldown_bars": 96,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 96,
      +          "short_cooldown_bars": 32,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 32
      +        },
      +        "5m": {
      +          "long_cooldown_bars": 480,
      +          "long_loss_limit": 6,
      +          "long_window_bars": 480,
      +          "short_cooldown_bars": 180,
      +          "short_loss_limit": 4,
      +          "short_window_bars": 180
      +        }
      +      },
      +      "description": "Per-timeframe loss-streak cooldown windows (short/long loss limits and cooldown bar counts).",
      +      "properties": {
      +        "15m": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 320,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 320,
      +            "short_cooldown_bars": 120,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 120
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 320,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 320,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 120,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 120,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "1d": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 60,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 60,
      +            "short_cooldown_bars": 20,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 20
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 60,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 60,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 20,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 20,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "1h": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 144,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 144,
      +            "short_cooldown_bars": 48,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 48
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 144,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 144,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 48,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 48,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "30m": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 220,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 220,
      +            "short_cooldown_bars": 80,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 80
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 220,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 220,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 80,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 80,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "4h": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 96,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 96,
      +            "short_cooldown_bars": 32,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 32
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 96,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 96,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 32,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 32,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "5m": {
      +          "additionalProperties": true,
      +          "default": {
      +            "long_cooldown_bars": 480,
      +            "long_loss_limit": 6,
      +            "long_window_bars": 480,
      +            "short_cooldown_bars": 180,
      +            "short_loss_limit": 4,
      +            "short_window_bars": 180
      +          },
      +          "properties": {
      +            "long_cooldown_bars": {
      +              "default": 480,
      +              "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_loss_limit": {
      +              "default": 6,
      +              "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "long_window_bars": {
      +              "default": 480,
      +              "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_cooldown_bars": {
      +              "default": 180,
      +              "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_loss_limit": {
      +              "default": 4,
      +              "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +              "maximum": 100,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +              "x-mangrove-status": "tunable"
      +            },
      +            "short_window_bars": {
      +              "default": 180,
      +              "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +              "maximum": 10000,
      +              "minimum": 1,
      +              "type": "integer",
      +              "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +              "x-mangrove-status": "tunable"
      +            }
      +          },
      +          "required": [
      +            "short_window_bars",
      +            "long_window_bars",
      +            "short_loss_limit",
      +            "long_loss_limit"
      +          ],
      +          "type": "object"
      +        },
      +        "cadence_reference": {
      +          "description": "Server-selected strategy cadence; metadata rather than a timeframe entry.",
      +          "type": "string"
      +        }
      +      },
      +      "type": [
      +        "object",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Tighter limits pause trading sooner after a losing streak; looser limits keep trading through drawdowns.",
      +      "x-mangrove-map-value-schema": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "long_cooldown_bars": {
      +            "description": "Bars to deny new entries once long_loss_limit trips. Also the latch duration a drawdown breaker trip uses.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_cooldown_bars, and it doubles as the drawdown breaker's cooldown, so raising it lengthens that halt too.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_loss_limit": {
      +            "description": "Consecutive losses inside long_window_bars that trip the long cooldown. Should exceed short_loss_limit, or the long rule never fires first.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the longer pause sooner; higher reserves it for a deeper losing streak.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "long_window_bars": {
      +            "description": "Lookback, in bars, over which long_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "As short_window_bars, over the longer horizon.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_cooldown_bars": {
      +            "description": "Bars to deny new entries once short_loss_limit trips. Positions already open still exit.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Longer sits out more of a bad regime at the cost of missing the recovery; shorter resumes sooner.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_loss_limit": {
      +            "description": "Consecutive losses inside short_window_bars that trip the short cooldown.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Lower trips the cooldown sooner after a losing run; higher tolerates more losses before pausing.",
      +            "x-mangrove-status": "tunable"
      +          },
      +          "short_window_bars": {
      +            "description": "Lookback, in bars, over which short_loss_limit is counted.",
      +            "maximum": 10000,
      +            "minimum": 1,
      +            "type": "integer",
      +            "x-mangrove-effect": "Wider counts losses over more history, so the limit trips more readily; narrower makes it a burst detector.",
      +            "x-mangrove-status": "tunable"
      +          }
      +        },
      +        "required": [
      +          "short_window_bars",
      +          "long_window_bars",
      +          "short_loss_limit",
      +          "long_loss_limit"
      +        ],
      +        "type": "object"
      +      },
      +      "x-mangrove-status": "tunable"
      +    },
      +    "cooldown_model": {
      +      "default": "trades",
      +      "description": "Loss-streak breaker model. 'bars' counts losing closes inside rolling windows of the primary timeframe (cooldown_config). 'trades' counts consecutive losing closes and realized loss amount, pauses for circuit_breaker bars of the primary timeframe (at least pause_min_hours and at most pause_max_days), and stops after repeated pauses (circuit_breaker). An absent model adopts the canonical 'trades' defaults; explicit 'bars' retains the legacy model.",
      +      "enum": [
      +        "bars",
      +        "trades",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "'trades' trips on trade count and loss size regardless of how far apart trades are spaced; 'bars' trips only when losses land inside the window. cooldown_config is ignored under 'trades'.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "daily_momentum_limit": {
      +      "default": 3,
      +      "description": "Daily momentum-based trade limit.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 100,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher permits more momentum-driven entries per day; lower throttles them.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "enable_volatility_adjustment": {
      +      "default": false,
      +      "description": "Toggles volatility-based position scaling (default false).",
      +      "type": [
      +        "boolean",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "When true, positions are scaled down by target_volatility / (atr/entry) if ATR%% exceeds target; only reduces size, never increases.",
      +      "x-mangrove-status": "gated"
      +    },
      +    "exit_on_loss_after_bars": {
      +      "default": 1000,
      +      "description": "Exit a losing position after this many bars.",
      +      "maximum": 10000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower cuts losers sooner; higher gives them more time to recover.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "exit_on_profit_after_bars": {
      +      "default": 1000,
      +      "description": "Exit a winning position after this many bars.",
      +      "maximum": 10000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower banks winners sooner; higher lets them run.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "initial_balance": {
      +      "default": 10000,
      +      "description": "Starting balance for the backtest/simulation (default $10,000).",
      +      "maximum": 1000000000,
      +      "minimum": 25,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Scales absolute dollar figures; not a strategy-character knob.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "max_drawdown_halt_limit": {
      +      "default": 0.2,
      +      "description": "Permanent capital-floor entry halt (0.20 = 20%). Closed, realized equity is compared with cumulative gross deposits (execution_state.cumulative_deposits), not a rolling peak or the signed net-funding balance; withdrawals do not reduce this reference. Legacy requests without cumulative_deposits use execution_config.initial_balance. The shared live/paper evaluator checks before each bar and latches execution_state.halt. New alpha entries and v3 core allocations are denied, while authoritative positions retain protective exits and exits_pending until physically flat. Engine-owned strategies become inactive only after that book is flat; caller-owned executors retain their exit monitor. An explicit manual restart is required to clear the latch. Backtests enforce the same floor when evaluate_bar receives enforce_capital_floor=True, managing open-position exits through the final bar. Applies to both cooldown models; null disables new floor trips, while an existing halt remains latched.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower protects more of gross deposited capital before a permanent entry halt; higher tolerates a deeper realized loss. This does not resize positions or stop protective exit evaluation. Do not add a separate floor where the shared evaluator enforces it.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "max_drawdown_limit": {
      +      "default": 0.2,
      +      "description": "Peak-relative entry pause (0.20 = 20%). The canonical 'trades' model measures marked equity against its high-water mark. A breach starts one drawdown pause and strike; circuit_breaker.drawdown_pause_bars defaults to 72 primary bars, clamped to pause_min_hours and pause_max_days (24 hours and 14 days by default). At drawdown-pause expiry the peak re-baselines; a reduced-size alpha resume window opens only once no pause remains and no permanent halt is latched. Explicit 'bars' retains the legacy closed-equity measurement and per-timeframe long cooldown. Both models deny new entries while allowing existing positions to exit; automatic v3 core allocations honor the hold too. null disables new drawdown trips.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower pauses entries after a smaller drawdown; higher tolerates a deeper drawdown. The shared entry breaker enforces this in single/bulk live and paper evaluation, v3 core allocation and backtests built with risk_manager_from_execution_config. Alpha resume sizing is a separate control; do not add a second drawdown stop.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "max_hold_bars": {
      +      "default": 1000,
      +      "description": "Maximum bars to hold any position before a forced exit.",
      +      "maximum": 10000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher lets trades run longer; lower forces earlier time-based exits.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "max_hold_time_hours": {
      +      "default": null,
      +      "description": "Maximum position hold time in hours (null = no limit).",
      +      "exclusiveMinimum": 1,
      +      "maximum": 8760,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Lower forces earlier time-based exits; null/higher lets trades run indefinitely on time.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "max_open_positions": {
      +      "default": 10,
      +      "description": "Maximum concurrent open positions.",
      +      "maximum": 1000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher allows more simultaneous exposure (more diversification but more aggregate risk); lower is more selective with less aggregate exposure.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "max_risk_per_trade": {
      +      "default": 0.01,
      +      "description": "Fraction of account equity risked per trade (0.01 = 1%). Position size is derived from this and the stop distance.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher risks more per trade: bigger positions, larger gains AND larger drawdowns. Lower is more conservative: smaller positions, smaller swings.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "max_trade_amount": {
      +      "default": 10000000,
      +      "description": "Absolute cap on dollar size per trade.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1000000000000,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Size guardrail; rarely binding.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "max_trades_per_day": {
      +      "default": 50,
      +      "description": "Daily trade cap.",
      +      "maximum": 1440,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher permits more churn; lower throttles activity.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "max_units_per_trade": {
      +      "default": 1000000,
      +      "description": "Absolute cap on units per trade.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1000000000000,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Size guardrail; rarely binding.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "min_asset_balance": {
      +      "description": "position_size_calc 'v3' only. Minimum asset balance, in asset units, the strategy holds outside open trades.",
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher keeps more of the asset out of reach of sell trades and core sells, and takes more cash to reach; lower frees more of the asset for trading.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "min_balance_days": {
      +      "description": "position_size_calc 'v3' only. Number of equal daily orders used to bring a side up to its minimum balance.",
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher spreads the minimum-balance orders over more days at smaller size; lower reaches the minimum sooner with larger orders.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "min_balance_threshold": {
      +      "default": 0.1,
      +      "description": "Cash reserve fraction held back from new entries (0.1 = 10%). v1 reserves this fraction of cash; v2 reserves this fraction of account value (cash + open positions at market). An entry may only use cash above the reserve; when no cash is deployable the entry is denied (insufficient_cash / insufficient_cash_v2_account_reserve). It never halts the strategy and never closes positions.",
      +      "exclusiveMaximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher keeps more cash idle and makes entries smaller or rarer as the account shrinks; lower lets entries use more of the balance. Not a drawdown stop; see max_drawdown_limit and max_drawdown_halt_limit.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "min_cash_balance": {
      +      "description": "position_size_calc 'v3' only. Minimum cash balance the strategy holds after the worst-case loss of every open trade.",
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher keeps more cash out of reach of buy trades and core buys, so entries are smaller or rarer; lower frees more cash for trading.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "min_stop_distance_pct": {
      +      "default": 0.005,
      +      "description": "Hard floor on stop distance as a fraction of entry price (crypto minimum), applied after ATR sizing.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher enforces a wider minimum stop; lower allows tighter stops down to the floor.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "min_trade_amount": {
      +      "default": 25,
      +      "description": "Minimum trade size in dollars; smaller intended trades are skipped.",
      +      "maximum": 1000000,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher skips more small signals; lower allows smaller trades.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "position_size_calc": {
      +      "default": "v2",
      +      "description": "Sizing-engine version ('v1', 'v2' or 'v3'). Pinned at creation and immutable. 'v3' holds an asset balance and a cash balance, sizes against equity net of open risk, and requires the position_size_calc 'v3' parameters.",
      +      "enum": [
      +        "v1",
      +        "v2",
      +        "v3",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Not a magnitude knob; selects the sizing algorithm. Do not change on an existing strategy.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "profit_threshold_pct": {
      +      "default": 0.05,
      +      "description": "Profit threshold (5%% default) above which a position counts as 'winning' for the time-based exit logic.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher requires a larger gain before a position is treated as winning; lower treats smaller gains as wins.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "rebalance_band": {
      +      "description": "position_size_calc 'v3' only. Absolute deviation of the asset weight from target_asset_weight that triggers a rebalance order (0.05 = 5 points).",
      +      "exclusiveMaximum": 1,
      +      "exclusiveMinimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher lets the split drift further before a rebalance order, so fewer core orders; lower holds the split closer to target with more core orders and more fees.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "reward_factor": {
      +      "default": 2,
      +      "description": "Risk/reward target. Take-profit distance = reward_factor * stop_distance.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 100,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher sets a wider profit target: lower win rate but bigger wins. Lower sets a tighter target: higher win rate but smaller wins.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "stop_gap_allowance": {
      +      "description": "position_size_calc 'v3' only. Fraction of the stop price a stop fill is assumed to miss by when computing the worst-case loss of a trade (0.01 = 1%).",
      +      "exclusiveMaximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher counts more risk per open trade, leaving less available cash and smaller positions; lower counts less.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "stop_model": {
      +      "default": "atr_width_dial",
      +      "description": "Which stop model the strategy uses: 'atr_width_dial' (one parameter, volatility_tolerance, positioned on the ATR width) or 'weighted_atr' (superseded: a weighted blend of two ATRs, capped). Pinned at creation and immutable.",
      +      "enum": [
      +        "atr_width_dial",
      +        "weighted_atr",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Not a magnitude knob; selects the stop algorithm. Do not change on an existing strategy -- it would move every stop the strategy takes.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "taker_fee_rate": {
      +      "description": "position_size_calc 'v3' only. Venue fee per fill as a fraction of notional, charged in cash (0.004 = 0.4%).",
      +      "exclusiveMaximum": 0.1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher counts more cost per fill, raising the risk of each trade and lowering available cash. Models the venue; not a strategy-character knob.",
      +      "x-mangrove-status": "guardrail"
      +    },
      +    "target_asset_weight": {
      +      "description": "position_size_calc 'v3' only. Target share of core value held in the asset (0.8 = 80% asset, 20% cash; 0 = all cash).",
      +      "exclusiveMaximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher holds more of the asset and less cash; lower holds more cash. The daily core order moves the split back to this value once it drifts past rebalance_band. At 0 with no asset held, no core order is placed and only buy trades can pass.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "target_volatility": {
      +      "default": 0.1,
      +      "description": "Target volatility (0.10 = 10%). ONLY active when enable_volatility_adjustment is true (default false). When active, scales position size down if ATR%% of entry exceeds the target (never up).",
      +      "exclusiveMinimum": 0,
      +      "maximum": 1,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "With the gate off (the default), changing this has no effect. With it on, lower scales positions down more aggressively in high volatility.",
      +      "x-mangrove-gate-field": "enable_volatility_adjustment",
      +      "x-mangrove-gate-required": true,
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "gated"
      +    },
      +    "volatility_mode": {
      +      "default": "stddev",
      +      "description": "Unused (retained for backward compatibility). Volatility is derived from ATR.",
      +      "enum": [
      +        "stddev",
      +        "atr",
      +        null
      +      ],
      +      "type": [
      +        "string",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "No runtime effect. Do not tune.",
      +      "x-mangrove-status": "unused"
      +    },
      +    "volatility_tolerance": {
      +      "default": 0.5,
      +      "description": "Where on the ATR width the stop is taken, as the ATR_long-vs-ATR_short contribution ratio: 0 is all short end (0.5x the signal timeframe's ATR), 1 is all long end (2x the daily ATR). Interpolated geometrically, so the value is exactly the long end's share of log(stop) and each 0.1 is the same multiplicative step. Replaces atr_short_weight, atr_long_weight and atr_cap_multiplier.",
      +      "maximum": 1,
      +      "minimum": 0,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher widens the stop, and because position size is the risk budget divided by the stop distance, exposure shrinks in exact inverse proportion at the SAME risk. Low means many units with little room to be wrong and frequent stop-outs; high means few units that are hard to shake out but need a much larger move to reach the same reward. Both risk max_risk_per_trade.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "tunable"
      +    },
      +    "volatility_window": {
      +      "default": 24,
      +      "description": "Unused (retained for backward compatibility). ATR windowing is controlled by atr_period.",
      +      "maximum": 1000,
      +      "minimum": 1,
      +      "type": [
      +        "integer",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "No runtime effect. Do not tune.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "unused"
      +    },
      +    "weekly_momentum_limit": {
      +      "default": 3,
      +      "description": "Weekly momentum-based trade limit.",
      +      "exclusiveMinimum": 0,
      +      "maximum": 100,
      +      "type": [
      +        "number",
      +        "null"
      +      ],
      +      "x-mangrove-effect": "Higher permits more momentum-driven entries per week; lower throttles them.",
      +      "x-mangrove-input-coercion": "Top-level validate_execution_config accepts finite numeric strings; integer fields require whole values. Version-specific checks remain separate.",
      +      "x-mangrove-status": "guardrail"
      +    }
      +  },
      +  "title": "Execution configuration",
      +  "type": "object",
      +  "x-mangrove-boundary-validation": "top-level numeric bounds after legacy coercion; null means unset"
      +}
  5. First observed

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the annotations: server-side regime checking that can refuse the save, exact-value preservation versus server defaults, dedupe on repeat saves via the `created` field, and the draft lifecycle that only exits when a backtest clears the threshold spec. Annotations only declare readOnly=false, destructive=false, openWorld=false. One mild tension: idempotentHint=false while the description says a second identical save returns the first rather than duplicating, which reads closer to idempotent — not a hard contradiction, but worth reconciling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded on parameters and prohibitions, with the lifecycle and dedupe facts at the end. Nearly every sentence carries load, though the instruction to preserve user choices and explain agent-selected adjustments is restated (once in prose, once in the constraints schema description) and the appended x402 access note is orthogonal to tool selection.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 12-parameter tool with nested objects and no output schema, the description covers the failure modes an agent must anticipate (regime refusal, invented signal names, out-of-range params) and names the `created` response field. It stops short of describing the rest of the return payload or what a saved draft exposes to downstream calls, which the absent output schema would otherwise require.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description nevertheless adds real semantics the schema does not: which parameters select sweep mode versus compose mode, that params default from the library when omitted, that signal names must resolve to real library entries, and that venue/quote_token come from the source run unless overridden. The large nested `constraints` object is deferred to the execution-config contract rather than explained, which is reasonable but leaves it wholly schema-driven.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource and explicitly covers the two distinct modes: promoting a sweep pick (source_experiment_id + source_run_index) and composing a strategy from library signals. The scope — draft-only, not tradeable until backtest passes — is stated outright, so an agent knows exactly what this tool produces and how it differs from build_strategy_for_regime or update_strategy.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Routing is explicit: sweep picks pass source_experiment_id and source_run_index, otherwise compose from signals with strategy_name, asset, and entry/exit signals. It names a prerequisite tool ('Find real signal names with query_knowledge first; never invent one'), an explicit prohibition ('DO NOT pass a signal's role'), and a gated escape hatch ('regime_override ... only ever on the person's explicit say-so'), plus when to omit market_data_venue/quote_token.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.