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"
+}