Which limits are on by default
The short answer: two of nine. This page is the long answer, and a starting configuration you can reason about.
The table
| Gate | State out of the box | What "off" means |
|---|---|---|
max_capital_allocation | On, cannot be disabled | |
available_capital | On, cannot be disabled | |
max_order_value | Off | Single-order size is bounded only by available capital |
per_trade_risk | Off | Money at risk per trade is bounded only by position size |
max_open_positions | Off | Unlimited concurrent positions, up to the capital ceiling |
max_trades_per_day | Off | Unlimited entries per day |
max_consecutive_losses | Off | The strategy trades through any losing run |
daily_loss_limit | Off | No daily circuit breaker |
mark_to_market_loss | Off | No unrealised-loss brake |
In the risk configuration a zero value turns the rule off. It does not mean "a limit of zero". There is no implicit default, no platform-wide fallback, and nothing in the interface announces that a rule you did not configure is a rule that will not run.
Why it is built this way
Two reasons, and both are defensible on their own terms, which is exactly why the behaviour needs documenting rather than fixing quietly.
Backwards compatibility. The convention predates the current pipeline: the original
max_trades gate and the environment-level notional check both treated zero as "unset". A
strategy carrying no risk configuration therefore behaves exactly as it did before the
pipeline existed. Changing that would silently alter live strategies.
Fail-open parsing. The configuration parser is deliberately defensive: a malformed or absent risk payload yields a configuration with every rule disabled, and never errors. The reasoning is that a bad payload must never hard-block a strategy that is trying to place an exit. That is the right trade-off for availability, and it means a configuration you believe you set may not be in force if it failed to parse.
The practical consequence: verify your limits on the strategy's risk panel. Do not infer them from what you typed into the chat.
What you always get, configuration or not
Do not read the table above as "there is no protection". Three things hold unconditionally:
-
Capital isolation. A strategy trades only its own allocation. It cannot borrow from another strategy, cannot exceed the allocation, and cannot place an order it cannot fund. Gates 8 and 9, neither of which can be disabled.
-
Stop-loss and take-profit inside the strategy. These are part of the strategy object, written at build time, simulated in the backtest and read by the live engine. They are not gates and they do not appear in the table because they are not optional in the same sense. If your strategy has a stop, the engine acts on it.
-
Exits are never blocked. No gate can prevent a strategy from closing a position.
A starting configuration
This is a conservative baseline, not a recommendation about what is right for you. Every value here is a decision about your own capital and you should set it deliberately.
| Gate | A sensible starting point | The reasoning |
|---|---|---|
per_trade_risk | 1% of allocation | The most consequential single limit. Bounds the damage of any one trade being wrong |
daily_loss_limit | 3% of allocation | Enough room for a normal losing day; stops a bad one becoming a very bad one |
max_consecutive_losses | 4 | Long enough not to trip on ordinary variance; short enough to notice a regime change |
max_open_positions | 1 to 3 | Start at 1 for a single-instrument strategy. More positions means more correlated exposure than the number suggests |
max_trades_per_day | 3 to 5 for intraday | Bounds churn. A signal firing every candle in a choppy market is the failure mode this catches |
max_order_value | ~30% of allocation | A backstop against a sizing error, not a sizing control |
mark_to_market_loss | An amount you would not sit through | Set it in money, because that is what you will feel |
State them in the builder in plain language and check them on the assembled strategy:
risk 1% per trade, stop trading if I'm down 3% in a day,
stop after 4 losses in a row, max 3 trades a day, one position at a time
Then read the assembled strategy object back and confirm each value landed. See Risk management in the builder.
How the values are read
The parser accepts several key spellings for compatibility, and the first one present wins. If you are setting configuration through an API rather than the builder, this is the precedence:
| Gate | Keys read, in order |
|---|---|
max_open_positions | risk_and_execution.max_trades, then risk.max_open_positions |
max_trades_per_day | risk_and_execution.max_trades_per_day, then risk.max_trades_per_day |
max_consecutive_losses | gates.max_consecutive_losses, then execution_controls.max_consecutive_losses, then risk.max_consecutive_losses |
daily_loss_limit | risk_and_execution.daily_loss_cap, then risk.daily_loss_cap_pct |
mark_to_market_loss | risk_and_execution, then risk, then execution_controls, then the top level |
per_trade_risk | risk_and_execution.per_trade_risk, then risk.max_risk_per_trade_pct |
max_order_value | risk_and_execution.max_order_value, then risk.max_order_value |
max_capital_allocation | risk_and_execution.max_capital_allocation, then risk.max_capital_allocation |
Note that max_open_positions reads a key named max_trades, and max_trades_per_day reads
max_trades_per_day. Those two are easy to confuse and mean different things: one is
concurrency, the other is daily velocity.
Verifying before you deploy
A three-item check, worth doing every time:
- Open the strategy's risk panel and read the enforced values. Not the chat transcript.
- Confirm the allocation is an amount whose worst-case drawdown you will tolerate.
- Run it in paper long enough to see at least one gate engage. A gate you have never seen trip is a gate you are trusting on faith.