Risk Management
Every strategy in MangroveAI has anexecution_config that controls risk management, position sizing, and trade lifecycle rules. This guide explains each field, how they interact, and how to tune them for your trading style.
How risk management works
When a strategy generates an entry signal, the execution engine does not just open a position — it calculates the appropriate position size based on your risk budget, sets a dynamic stop-loss using ATR, and enforces limits on how many positions you can hold, how long you can hold them, and how often you can trade. All of this is configured in theexecution_config object, which is stored with each strategy.
The execution_config object
Here is the completeexecution_config with default values. Each field is explained in the sections below.
If you do not provide
execution_config when creating a strategy, the API populates it with defaults from trading_defaults.json. You only need to include fields you want to override.Stop-loss calculation
The stop-loss determines where a losing trade is automatically closed. MangroveAI uses dynamic ATR-based stops by default.How dynamic ATR stops work
ATR (Average True Range) measures recent price volatility. A dynamic ATR stop-loss places the stop at a distance proportional to recent volatility:atr_volatility_factor is 2.0:
Relevant fields
| Field | Default | Description |
|---|---|---|
stop_loss_calculation | "dynamic_atr" | Stop-loss method. Use "dynamic_atr" for volatility-adjusted stops. |
atr_period | 14 | Number of bars to calculate ATR. Longer periods smooth out volatility spikes. |
atr_volatility_factor | 2.0 | Multiplier for ATR distance. Higher = wider stop = more room to breathe. |
Tuning the stop-loss
| Scenario | atr_volatility_factor | Effect |
|---|---|---|
| Tight risk control | 1.0 - 1.5 | Stops are close to entry. More trades get stopped out, but losses are small. |
| Standard | 2.0 | Balanced tradeoff. The default for most strategies. |
| Wide stops | 2.5 - 3.5 | Stops give the trade room to fluctuate. Fewer stop-outs, but larger individual losses. |
Take-profit calculation
Take-profit is calculated from the stop-loss distance and thereward_factor:
reward_factor: 2:
| Field | Default | Description |
|---|---|---|
reward_factor | 2 | Risk/reward ratio. A value of 2 means the take-profit target is 2x the stop-loss distance. |
reward_factor of 2 means you need to win only 34% of trades to break even (excluding fees). Combined with a reasonable win rate, this creates a positive expected value.
Position sizing
Position sizing determines how much capital to allocate per trade.Risk-based sizing
Themax_risk_per_trade field sets the maximum percentage of your account you are willing to lose on a single trade:
| Field | Default | Description |
|---|---|---|
max_risk_per_trade | 0.01 | Max risk per trade as a decimal (0.01 = 1% of account). |
min_trade_amount | 25 | Minimum trade size in dollars. Trades below this are skipped. |
min_balance_threshold | 0.1 | Minimum account balance as a fraction. Trading pauses if balance drops below this. |
Volatility-adjusted sizing
Optionally, position sizes can be scaled based on current volatility:| Field | Default | Description |
|---|---|---|
enable_volatility_adjustment | false | When true, position size is scaled inversely to volatility. |
volatility_window | 24 | Number of bars for volatility calculation. |
target_volatility | 0.02 | Target portfolio volatility level. |
volatility_mode | "stddev" | Volatility measure: "stddev" (standard deviation) or "atr". |
Position limits
These fields prevent over-concentration and overtrading:| Field | Default | Description |
|---|---|---|
max_open_positions | 10 | Maximum concurrent open positions. New entries are blocked once this limit is reached. |
max_trades_per_day | 50 | Daily trade cap. Prevents runaway trading in volatile markets. |
Tuning for your style
| Trading style | max_open_positions | max_trades_per_day |
|---|---|---|
| Conservative | 1 - 3 | 5 - 10 |
| Moderate | 5 - 10 | 20 - 50 |
| Active | 10 - 20 | 50 - 100 |
Cooldown system
The cooldown system prevents a strategy from entering new positions after a losing streak. It uses a two-tier design — a short tier that catches acute streaks, and a long tier that catches sustained underperformance. Both tiers operate independently per asset.Two-tier design
| Tier | Purpose | Trips when… |
|---|---|---|
| Short | Detects an acute losing streak | short_loss_limit losses occur within the last short_window_bars bars |
| Long | Detects sustained underperformance | long_loss_limit losses occur within the last long_window_bars bars |
short_window_bars bars; tripping the long tier blocks entries for long_window_bars bars. This means the window bar count serves double duty — it is both the rolling lookback and the cooldown duration.
If a short-tier trip occurs while a long cooldown is already active, the longer cooldown is preserved. Cooldowns never shorten an already-active block.
The cooldown_config block
cooldown_config is a dict keyed by primary timeframe. Each timeframe has four values:
| Key | Description |
|---|---|
short_loss_limit | Number of losses in the short window that trips the short-tier cooldown |
long_loss_limit | Number of losses in the long window that trips the long-tier cooldown |
short_window_bars | Rolling lookback for the short tier AND the cooldown duration when short trips |
long_window_bars | Rolling lookback for the long tier AND the cooldown duration when long trips |
time_based_exits.max_hold_bars in execution_config.
Reading the defaults
For a 1h strategy with the defaults above:- Short tier: 4 losses in the last 48 bars (2 days) trips a 48-bar cooldown
- Long tier: 6 losses in the last 144 bars (6 days) trips a 144-bar cooldown
- Max hold is set separately via
execution_config.max_hold_bars(see Time-based exits below)
- Short tier: 4 losses in the last 180 bars (15 hours) trips a 180-bar cooldown
- Long tier: 6 losses in the last 480 bars (40 hours) trips a 480-bar cooldown
- Max hold is set separately via
execution_config.max_hold_bars(see Time-based exits below)
Tuning guidance
The defaults are calibrated for standard multi-timeframe use. Adjust based on your strategy’s expected win rate and trade frequency:- Higher
short_loss_limit: more tolerance for short losing streaks before cooling off - Lower
short_window_bars: narrower lookback — only very recent losses count - Larger
long_window_bars: spread the long-tier assessment over a wider history - Smaller
max_hold_bars(inexecution_config): force position turnover faster regardless of timeframe
Fallback (legacy keys)
Ifcooldown_config is absent from execution_config, or if the strategy’s primary timeframe is not a key in cooldown_config, the engine falls back to the legacy flat keys and emits a structured deprecation warning in the logs. See the deprecation notice at the top of this page for the migration mapping.
Time-based exits
These fields force positions to close after a certain number of bars, regardless of signals:| Field | Default | Description |
|---|---|---|
max_hold_bars | 50 | Maximum bars to hold any position. Forces exit after this limit. |
exit_on_loss_after_bars | 50 | Force-exit losing positions after this many bars. |
exit_on_profit_after_bars | 60 | Force-exit winning positions after this many bars. |
profit_threshold_pct | 0.05 | What counts as “winning” for exit_on_profit_after_bars. 0.05 = 5% unrealized profit. |
Example scenario
With defaults on a 1h timeframe:- A losing trade is forced closed after 50 bars (about 2 days)
- A winning trade (5%+ profit) is forced closed after 60 bars (about 2.5 days)
- Any position, regardless of P&L, closes after 50 bars (
max_hold_bars)
Putting it all together
Here is a complete example that creates a strategy with custom risk parameters — tighter stops, smaller position sizes, fewer concurrent positions, and explicit cooldown config for a 1h timeframe:- 0.5% risk per trade instead of 1% — halves position sizes
- 1.5x ATR stops instead of 2x — tighter exit on losses
- 2.5x reward factor — requires more upside before taking profit
- 3 max positions instead of 10 — less capital at risk simultaneously
- Explicit 1h cooldown_config — 3-loss short trip, 5-loss long trip, both tuned for conservative operation
Quick reference: all fields
| Field | Type | Default | Description |
|---|---|---|---|
max_risk_per_trade | number | 0.01 | Max risk per trade (0.01 = 1%) |
reward_factor | number | 2 | Risk/reward ratio for take-profit |
stop_loss_calculation | string | "dynamic_atr" | Stop method ("dynamic_atr" or "fixed") |
atr_period | int | 14 | ATR lookback period (bars) |
atr_volatility_factor | number | 2.0 | ATR multiplier for stop distance |
min_balance_threshold | number | 0.1 | Min balance fraction before trading pauses |
min_trade_amount | number | 25 | Min trade size in dollars |
max_open_positions | int | 10 | Max concurrent positions |
max_trades_per_day | int | 50 | Daily trade limit |
volatility_window | int | 24 | Bars for volatility calc |
target_volatility | number | 0.02 | Target portfolio volatility |
volatility_mode | string | "stddev" | Volatility method ("stddev" or "atr") |
enable_volatility_adjustment | bool | false | Scale position sizes by volatility |
max_hold_bars | int | 50 | Max bars for any position |
exit_on_loss_after_bars | int | 50 | Force-exit losers after N bars |
exit_on_profit_after_bars | int | 60 | Force-exit winners after N bars |
profit_threshold_pct | number | 0.05 | Threshold for “winning” (0.05 = 5%) |
cooldown_config | object | see defaults | Per-timeframe cooldown settings (see above) |
cooldown_bars | int | 24 | Deprecated. Use cooldown_config[tf].short_window_bars. |
daily_momentum_limit | number | 3 | Deprecated. Use cooldown_config[tf].short_loss_limit. |
weekly_momentum_limit | number | 3 | Deprecated. Use cooldown_config[tf].long_loss_limit. |
max_hold_time_hours | number/null | null | Deprecated. Use execution_config.max_hold_bars (bars) instead of hours. |
Next steps
- Create a strategy with custom risk parameters
- Run a backtest to see how risk settings affect performance
- Use the AI Copilot to get risk parameter suggestions