Pine Script strategy.risk: daily loss limit, max drawdown and position caps
How the six strategy.risk rules in Pine Script work: max intraday loss, max drawdown, max position size, daily order cap, losing-day streak and long-only or short-only entries, with a working example.
The strategy.risk functions add hard risk limits to a Pine Script strategy. They can stop new trades after a daily loss, close everything at a maximum drawdown, cap the position size, limit orders per day, pause after a run of losing days, or allow only long or only short entries. You call them once at the top of the script, and the Strategy Tester applies them to every bar of the backtest. SuperCharting enforces all six rules.
The six rules
| Function | What it does |
|---|---|
strategy.risk.allow_entry_in(value) | Allows entries in one direction only: strategy.direction.long, strategy.direction.short or strategy.direction.all |
strategy.risk.max_position_size(contracts) | The largest position the strategy may hold; bigger entries are trimmed, and entries at the cap are refused |
strategy.risk.max_intraday_filled_orders(count) | The most filled orders per trading day; new orders are refused once the count is reached |
strategy.risk.max_intraday_loss(value, type) | The largest loss allowed in one trading day; at the limit the position is closed and no new trades are taken until the next day |
strategy.risk.max_drawdown(value, type) | The largest drop from the equity high; at the limit everything is closed and the strategy stops for the rest of the backtest |
strategy.risk.max_cons_loss_days(count) | The most losing days in a row; after that the strategy stops for the rest of the backtest |
For max_intraday_loss and max_drawdown, type is strategy.percent_of_equity (a percentage) or strategy.cash (an amount in the account currency).
How each limit is checked
- Long or short only. With
allow_entry_in(strategy.direction.long), a short entry does not open a short. If a long is open, the short signal only closes it. - Daily loss. The loss is measured at the worst price inside each bar, not only at the close, so a bar that dips through the limit triggers it. The position is closed there, with the strategy's slippage, and trading resumes the next trading day.
- Drawdown. Checked against the highest equity reached so far, on bars where a trade closes. Once hit, the strategy is done for the run.
- Losing days. Counted when a new trading day starts. Once the count is reached, the strategy is done for the run.
In the Strategy Tester's list of trades, a position closed by a rule shows the exit Risk management close, so you can see where a limit cut in.
A working example
//@version=6
strategy("EMA cross with risk rules", overlay = true,
initial_capital = 100000, default_qty_type = strategy.percent_of_equity, default_qty_value = 10)
// Risk rules: long only, at most 2% lost in a day, stop at a 15% drawdown
strategy.risk.allow_entry_in(strategy.direction.long)
strategy.risk.max_intraday_loss(2, strategy.percent_of_equity)
strategy.risk.max_drawdown(15, strategy.percent_of_equity)
strategy.risk.max_intraday_filled_orders(6)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
plot(fast, "EMA 9", color.teal)
plot(slow, "EMA 21", color.orange)
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
strategy.close("Long")
Run it with and without the four strategy.risk lines and compare the two Strategy Tester reports. The net profit may be lower with the rules on, but the largest drawdown and the worst day should be smaller. That trade-off is the point of the rules. A backtest is not a promise of future results.
How to try it
- Open a chart, for example
NSE:NIFTYon the 15m interval. - Open the Pine Editor, paste the example and click Add to chart.
- Open the Strategy Tester to see the report, the list of trades and the equity curve.
- Change the limits in the script, for example
max_intraday_loss(1, ...), and add it again to compare.
The Strategy Tester guide explains every number in the report, and the free Pine Script checker checks a script without an account.
Frequently asked questions
What is the difference between max_intraday_loss and max_drawdown?
max_intraday_loss resets every trading day: after a bad day the strategy trades again the next day. max_drawdown is measured from the highest equity of the whole run and stops the strategy for good once reached.
Can I use cash amounts instead of percentages?
Yes. Pass strategy.cash as the type, for example strategy.risk.max_intraday_loss(5000, strategy.cash).
Where should strategy.risk calls go in the script?
Anywhere at the top level, usually right after strategy(). They are settings for the whole run, so calling them inside an if block is not needed.