Skip to content

Do an extra TradingView strategy calculation after an order fills

Do an extra TradingView strategy calculation after an order fills

Section titled “Do an extra TradingView strategy calculation after an order fills”

TL;DR
Use calc_on_order_fills to run your strategy logic again right after fills so stop-losses, alerts, and position data stay accurate.

DifficultyIntermediate
Time to implement10-15 min
CategoryStrategy Basics
//@version=5
strategy(
"Calc on fills demo",
overlay = true,
calc_on_order_fills = true
)
if ta.crossover(close, ta.ema(close, 20))
strategy.entry("Long", strategy.long)
Tip. `calc_on_order_fills` defaults to `false`. Turning it on re-runs your script the moment an order fills, after regular per-bar calculations.

Strategies normally execute once per bar (or per tick if enabled). When an order fills, TradingView updates position information but does not automatically re-run your script. Enabling calc_on_order_fills makes PineScript immediately evaluate post-fill logic—useful for stop-loss adjustments, pyramiding, or sending alerts that depend on the fresh fill data.

  • How calc_on_order_fills changes the strategy evaluation schedule
  • Scenarios where post-fill logic is essential (pyramiding, stop management)
  • How to test that the extra calculation is happening
  • Guardrails to avoid redundant orders on the fill calculation
CallPurpose
strategy(calc_on_order_fills=true)Enables post-fill executions.
strategy.opentradesAccesses open trade information after the fill.
strategy.position_sizeShows updated position size once the order posts.
strategy.closedtradesAllows reacting to exits the moment they close.
alert()Fire alerts in the fill pass without waiting for the next bar.
  1. Enable the extra calculation
    Turn the feature on at strategy declaration.

    strategy("Fill-aware strategy", calc_on_order_fills = true)
  2. Detect when you are on the fill callback
    Pine exposes strategy.opentrades and other state immediately in the fill pass. Combine them with strategy.opentrades == strategy.opentrades style checks or the strategy.opentrades.entry_bar_index to ensure you only run fill-specific logic once.

    isFillPass = strategy.opentrades > 0 and strategy.opentrades.entry_bar_index(strategy.opentrades - 1) == bar_index
  3. Adjust stops or raise alerts when fills occur
    Use the fill pass to position protective orders or send notifications.

    if isFillPass
    // Move stop to break even immediately after entry fills
    entryPrice = strategy.opentrades.entry_price(strategy.opentrades - 1)
    stop = entryPrice * 0.98
    strategy.exit("Protect", from_entry="Long", stop=stop)
    alert("Entry filled at " + str.tostring(entryPrice, format.mintick))
Note. Fills on the same bar as the entry may trigger both the bar calculation and the fill calculation. Use flags (e.g., `var bool filledThisBar`) to prevent duplicate orders.
//@version=5
strategy(
"Fill aware example",
overlay = true,
pyramiding = 1,
calc_on_order_fills = true
)
length = input.int(50, "Baseline EMA")
fast = ta.ema(close, length / 2)
slow = ta.ema(close, length)
plot(fast, "Fast EMA", color=color.green)
plot(slow, "Slow EMA", color=color.orange)
longSignal = ta.crossover(fast, slow)
exitSignal = ta.crossunder(fast, slow)
if longSignal
strategy.entry("Long", strategy.long)
if exitSignal
strategy.close("Long")
// Fill-aware logic
var lastFillBar = na
if strategy.opentrades > 0
idx = strategy.opentrades - 1
fillBar = strategy.opentrades.entry_bar_index(idx)
if fillBar == bar_index and fillBar != lastFillBar
entry = strategy.opentrades.entry_price(idx)
stop = entry * 0.98
strategy.exit("Protective stop", from_entry="Long", stop=stop)
alert("Long filled at " + str.tostring(entry, format.mintick))
lastFillBar := fillBar
Why this works.
  • The fill callback runs immediately after the entry, so the protective stop is placed without waiting for the next bar.
  • The `lastFillBar` guard stops duplicate stop orders when fills happen intrabar.
  • Alerts fire with the final fill price, not a stale bar value.
  • Combine calc_on_every_tick=true with calc_on_order_fills=true only when necessary—every tick followed by every fill can be computationally expensive.
  • Always guard fill logic with flags to avoid duplicate entries/exits inside the same bar.
  • Use strategy.closedtrades.exit_bar_index() to react to exits in the same way you handle entries.
  • Remember: fill calculations happen after the standard bar calculation. Plan your state updates accordingly.

I see duplicate stop orders after enabling calc_on_order_fills

Section titled “I see duplicate stop orders after enabling calc_on_order_fills”

Set a var flag or compare the entry_bar_index to ensure the fill logic only runs once per fill event.

Does this feature work in the live broker bridge?

Section titled “Does this feature work in the live broker bridge?”

Yes. The fill callback triggers in backtesting and live trading sessions, making it suitable for live alerting or automation through webhooks.

  • calc_on_order_fills triggers an extra execution immediately after each fill.
  • Use the extra pass to adjust stops, update risk metrics, or send alerts based on the executed price.
  • Guard against duplicate orders by tracking the bar index of fills.
  • Combine with strategy.position_size and strategy.closedtrades to observe positions in real time.

Adapted from tradingcode.net, optimised for Algo Trade Analytics users.