You run a strategy with a stop and a target set close together on a daily chart. The report shows a handful of trades that exit on the stop. You open the same bar on a one-hour chart and the price visibly reached the target first. Nothing is broken in your code. The Strategy Tester simply had to guess what happened inside a bar it only knew four numbers about, and on this bar it guessed the other way.
The use_bar_magnifier option is TradingView's answer to that guess. It is one argument in the strategy() declaration, and it changes how historical fills are decided, which means it can change entries, exits, and every statistic built on them. This post explains what the emulator does without it, what the magnifier replaces that behavior with, where it still falls back to guessing, and how to check for yourself whether it matters for a given script.
What the emulator knows about a bar
A historical bar gives the emulator four prices: open, high, low, and close. It does not know the order in which price visited them. Yet a bracket order with both a stop and a limit needs exactly that order. If the bar's range contains both levels, the order that was touched first is the order that fills.
TradingView's strategy documentation describes the default assumption. If the open is closer to the high than to the low, the emulator assumes price moved open, then high, then low, then close. If the open is closer to the low, it assumes open, low, high, close. It is a reasonable rule and it is right often enough, but it is a rule applied to four numbers, not a record of what happened.
The emulator also assumes there are no gaps inside a bar, so any price in the bar's range can fill a pending order. When price crosses an order level in the gap between one bar's close and the next bar's open, the order fills at the next open. Neither assumption is a bug. They are the price of working from chart bars only, and they are the reason the same strategy can look different on a different timeframe.
What the magnifier changes
With the magnifier on, the emulator uses open, high, low, and close values from a suitable lower timeframe, when it can, instead of relying only on the chart's own bars. Those extra prices give it more points on the path, so it can see which level was reached first rather than inferring it from where the open sat.
The documentation gives a clear example: on a weekly chart, the default emulator fills a "Buy" order one bar after the order is created and the matching "Exit" order several bars later. With the magnifier enabled it works from daily bars and can fill both orders within the same weekly bar. Same script, same chart, different trade list, purely because the emulator had finer information.
Two related effects are worth knowing. First, the script can run additional executions on each historical bar, depending on the script execution settings, so logic that depends on intrabar state may behave differently. Second, the setting does not apply to the 1S or 1T timeframes: a 1T chart always analyzes one tick per bar and a 1S chart always analyzes four ticks per bar.
Turning it on
There are two places. In the interface, set Bar detalization to "High" in the strategy's settings or at the top of the strategy report. In code, add use_bar_magnifier = true to the declaration, which makes high detail the default for that script. TradingView's documentation states that only users on the Premium and Ultimate plans can use high historical bar detail, so check your own plan before assuming the option will take effect.
The argument is a constant, so it cannot be driven by an input.bool(). If you want to compare both modes, you flip it in the declaration or in the settings and run the script twice, which is exactly what the next sections do.
//@version=6
strategy(
"Magnifier Demo",
overlay = true,
use_bar_magnifier = true,
initial_capital = 10000,
default_qty_type = strategy.percent_of_equity,
default_qty_value = 10)
fastLen = input.int(20, "Fast EMA", minval = 1)
slowLen = input.int(50, "Slow EMA", minval = 1)
stopPct = input.float(1.0, "Stop %", minval = 0.1, step = 0.1)
targetPct = input.float(2.0, "Target %", minval = 0.1, step = 0.1)
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if strategy.position_size > 0
entryPrice = strategy.position_avg_price
strategy.exit(
"Exit",
"Long",
stop = entryPrice * (1 - stopPct / 100),
limit = entryPrice * (1 + targetPct / 100))
plot(fast, "Fast", color = color.teal)
plot(slow, "Slow", color = color.orange)This is an ordinary crossover entry with a percentage stop and a percentage target, which is the shape of script where the magnifier matters most. On a daily chart a bar often spans both the stop and the target. Which one fills first decides whether the trade is a loser or a winner, and the default path guess and the magnified path can disagree.
Where it still falls back to guessing
The magnifier is not unlimited. TradingView's documentation says a script can request at most 200,000 bars from any lower timeframe. Because of that cap, some symbols and timeframes will not have intrabar coverage for their earliest bars. On bars that lack intrabar data, the emulator falls back to its default assumptions.
The practical consequence is that a single report can mix two regimes: precise fills on recent bars and guessed fills on old ones. If you load a long history on a small chart timeframe, the early part of your sample was probably tested without the benefit. That does not make the early results wrong, but it does mean you cannot assume uniform fill quality across the whole date range. If the first trades look very different from the last ones, check the date where intrabar data starts before blaming your logic.
It also helps to remember what the magnifier is not. It does not model slippage, commission, partial fills, or liquidity. It improves the emulator's knowledge of the price path. The order of events inside the bar is better; the realism of the fill price is still your job, which is covered in slippage and commission.
How the stop and target order flips
To see the effect concretely, picture a daily bar that opens at 100, with a long position entered earlier at 100, a stop at 99 and a target at 102. The bar's high is 102.5 and its low is 98.5. Both levels are inside the range.
Under the default rule the emulator compares distances. With the open at 100, a high of 102.5 and a low of 98.5, the open is closer to the low, so it assumes the low came first, which fills the stop. Had the low been 97, it would assume the high came first and fill the target. The rule looks only at the open, the high, and the low.
With the magnifier, the emulator can walk the lower timeframe bars inside that day. If the hourly bars show price dipping to 98.5 in the first two hours and only reaching 102.5 in the afternoon, the stop fills first, regardless of where the open sat. If they show the rally came first, the target fills. The trade can flip from a loss to a win, or the reverse, with no change to your code.
This is why scripts built around tight bracket exits are the most sensitive, and why scripts that only act on the close of the bar are usually the least. A strategy that enters and exits at market on bar closes is barely helped by finer intrabar data, because there is nothing intrabar for the emulator to decide.
Measuring how many trades are affected
You do not have to guess how much a given script depends on this. One honest measure is how many trades open and close within the same bar, because those are the trades whose result depends entirely on the intrabar path. The script below counts them and draws the result on the last bar.
//@version=6
strategy("Same-Bar Trade Counter", overlay = true, use_bar_magnifier = true, default_qty_type = strategy.percent_of_equity, default_qty_value = 10)
fastLen = input.int(10, "Fast EMA", minval = 1)
slowLen = input.int(30, "Slow EMA", minval = 1)
stopPct = input.float(0.8, "Stop %", minval = 0.1, step = 0.1)
tpPct = input.float(1.6, "Target %", minval = 0.1, step = 0.1)
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if strategy.position_size > 0
px = strategy.position_avg_price
strategy.exit("Exit", "Long", stop = px * (1 - stopPct / 100), limit = px * (1 + tpPct / 100))
var label info = na
if barstate.islast
int total = strategy.closedtrades
int sameBar = 0
if total > 0
for i = 0 to total - 1
if strategy.closedtrades.entry_bar_index(i) == strategy.closedtrades.exit_bar_index(i)
sameBar += 1
label.delete(info)
info := label.new(bar_index, high, "Closed: " + str.tostring(total) + "\nSame-bar: " + str.tostring(sameBar), style = label.style_label_down)Run it twice, once with use_bar_magnifier = true and once with it removed or set to false, and compare the two labels along with the trade count and net result in the Strategy Tester. The total > 0 guard matters: a loop written as 0 to total - 1 counts downward when the total is zero, which would read trade numbers that do not exist.
If the count of same-bar trades is small and the two runs match closely, the magnifier is a minor detail for that script. If the counts and results move noticeably, the script's results depend on intrabar order and you should treat any single run with caution. The comparison costs two runs and tells you more than any rule of thumb.
Reading the results carefully
A change in results after enabling the magnifier is not proof that the new number is the truth. It is evidence that the emulator now has better information, and for most scripts that means the new run is closer to what the order path would have been. It is still a simulation. The Strategy Tester metrics guide covers what each statistic does and does not tell you, and why backtest results differ from live trading covers the gaps that remain even with perfect intrabar data.
A few habits make this less confusing. Keep the setting the same when you compare two versions of a strategy, because changing both your logic and the fill model at once makes the difference unreadable. Note the setting next to every result you save. And if a strategy only looks acceptable under one fill model, that sensitivity is itself information about how fragile it is. A related timing choice is covered in calc_on_every_tick, which changes when your script executes rather than how fills are decided, and the two interact on realtime bars.
Letting the AI editor set it up
If you want to add the option to an existing script, or just want to understand what a script's declaration is doing, the PineScripter editor can help. You describe the change in plain English, such as asking it to turn on the bar magnifier and add a same-bar trade counter, and it edits only the lines that change and checks the result for compile errors the way TradingView would. It also explains the script in plain English, which is useful when you inherit a strategy with a long declaration and are not sure which arguments matter. The PineScripter chart does not run strategies or simulate trades, so the actual comparison happens in TradingView's Strategy Tester. The code you get is yours to paste and keep.
Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.
Frequently asked questions
Does use_bar_magnifier work on every TradingView plan?
According to TradingView's strategy documentation, only Premium and Ultimate plans can use high historical bar detail. Check your own plan before relying on the setting.
Can I switch the bar magnifier on with an input?
No. It is an argument of the strategy() declaration, so you set it in the code or through the Bar detalization option in the strategy settings, and run the script again to compare.
Why do some early trades look different from recent ones?
TradingView limits a script to 200,000 bars from any lower timeframe, so early bars on some symbols and timeframes have no intrabar data. Those bars use the emulator's default assumptions.
Will the magnifier fix unrealistic fill prices?
No. It gives the emulator a better view of the price path inside a bar. It does not model slippage, commission, or liquidity, so those still need their own settings.
Does it matter for strategies that trade only on bar close?
Usually very little. If entries and exits happen at market on closes, there is little intrabar order for the emulator to decide.
Describe your indicator in plain English and get Pine Script that compiles →
Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.