TradingView Backtesting

Time-based stop loss: define the clock and the fill

A time-based stop loss requests an exit when a holding-time limit expires, even if price has reached neither a protective stop nor a profit target. Choose whether the limit counts chart bars, elapsed clock time or trading-day transitions. Start the holding timer at the actual entry fill, then distinguish when Pine detects expiry from when the exit order fills.

Draft a time-exit rule

Three clocks answer different questions

Write the timer unit into the strategy specification. A bar count measures observed chart bars. A timestamp difference includes nights, weekends and holidays. A trading-day count follows session boundaries and must state what counts as day one. These definitions can produce different exits from the same entry.

  • For an overnight session, midnight need not start a new trading day. On intraday charts, time_tradingday groups bars by the day on which their session ends.
  • If the rule means exit at the end of the second session, use a session-end rule. The second day transition in this example is detected during the third observed trading day, not at the second session close.
  • An exchange holiday with no bars produces no observed transition. A data outage can also hide a session, so this counter is not an independent exchange calendar.
ClockDefinition used hereBoundary
Completed holding barsCurrent bar index minus fill bar index plus one, evaluated at the closeThe entry bar counts as one. Missing bars do not advance the count.
Elapsed minutes(Bar closing timestamp minus entry-fill timestamp) / 60,000Closed-market time counts, but the script cannot evaluate a missing bar.
Trading-day transitionsCount observed changes of time_tradingday after the entry dayFriday to Monday is one transition when Monday is the next session, not three days.

Pine Script v6: one entry and a selectable timeout

Use this diagnostic on standard intraday time-based candles. Set the submission time inside loaded history; the script submits one market entry at the close of the first bar opening at or after that time. The timer starts from the eventual fill. It deliberately has no price stop, target or entry signal, so its trade demonstrates timing rather than a trading strategy.

  • Keep the calculation settings as declared for this experiment. One unit still needs sufficient initial capital for the selected symbol and contract point value; no trade can mean an unfunded order or missing history.
  • Bars mode includes the entry bar because this example fills at its opening tick. For entries filled mid-bar, the same formula counts a partial bar; redefine it if the rule requires complete bars after entry.
  • The optional closing-tick fill changes only the timeout close. It is a simulation setting, not a promise that a live order sent after a session close can fill at that close.
  • For pyramiding, partial fills or separate entry IDs, define whether each trade has its own timer or the whole position inherits the oldest fill. This one-trade example does not implement those policies.
One long trade; default close calculation and next-tick market fillspinescript
//@version=6
strategy("Holding timer diagnostic", overlay = true, pyramiding = 0,
     initial_capital = 100000, default_qty_type = strategy.fixed,
     default_qty_value = 1, calc_on_every_tick = false,
     calc_on_order_fills = false, process_orders_on_close = false)

submitFrom = input.time(timestamp("01 Oct 2026 09:25 -0400"), "Submit from")
clockMode = input.string("Bars", "Clock", options = ["Bars", "Minutes", "Trading days"])
maxBars = input.int(3, "Completed holding bars", minval = 1)
maxMinutes = input.int(12, "Elapsed minutes", minval = 1)
maxDays = input.int(1, "Trading-day transitions", minval = 1)
closeImmediately = input.bool(false, "Simulate timeout fill on closing tick")

if not timeframe.isintraday or not chart.is_standard
    runtime.error("Use standard intraday time-based candles.")

var bool submitted = false
var int lastTradingDay = na
var int dayTransitions = 0

if not submitted and time >= submitFrom
    strategy.entry("Long", strategy.long)
    submitted := true

int heldBars = na
float heldMinutes = na
bool expired = false
if strategy.opentrades > 0
    int fillBar = strategy.opentrades.entry_bar_index(0)
    int fillTime = strategy.opentrades.entry_time(0)
    if na(lastTradingDay)
        lastTradingDay := time_tradingday
        dayTransitions := 0
    else if time_tradingday != lastTradingDay
        dayTransitions += 1
        lastTradingDay := time_tradingday
    heldBars := bar_index - fillBar + 1
    heldMinutes := (time_close - fillTime) / 60000.0
    expired := clockMode == "Bars" ? heldBars >= maxBars : clockMode == "Minutes" ? heldMinutes >= maxMinutes : dayTransitions >= maxDays
    if expired
        strategy.close("Long", comment = "Time expiry", immediately = closeImmediately)
else
    lastTradingDay := na
    dayTransitions := 0

plot(heldBars, "Completed holding bars", display = display.data_window)
plot(heldMinutes, "Elapsed minutes", display = display.data_window)
plot(strategy.opentrades > 0 ? dayTransitions : na, "Trading-day transitions", display = display.data_window)
plotshape(expired, title = "Timeout detected", style = shape.xcross,
     location = location.abovebar, color = color.orange, text = "TIME")

A price-neutral sample that expires before either price exit

Assume a hypothetical long of 10 shares fills at $100 at 09:30. A separate price-only comparison has a $95 stop and $110 target already active. All prices below remain between those levels. Use full five-minute bars, no fees or slippage, and a 12-minute time limit. These are calculated expectations, not a historical TradingView result.

  • The deadline is 09:42, but a close-only calculation first sees it at 09:45. The price-only comparison still holds; the time exit realizes (99.70 - 100) × 10 = -$3 before costs.
  • Bars mode with a limit of three reaches the same decision on this continuous sample. That agreement does not make three bars equivalent to fifteen elapsed minutes on other sessions.
  • With the closing-tick option enabled, the hypothetical fill is $99.80 and gross P/L is -$2. The $1 difference comes from a different fill assumption, not a better timer.
  • At 09:45 the previous close and next open share a timestamp. Compare the bar and fill price as well as the timestamp; equal displayed times do not prove same-tick execution.
Observed barOHLCTimer at close
09:30 to 09:35100 / 101 / 99.50 / 100.205 minutes; holding bar 1
09:35 to 09:40100.20 / 100.80 / 99.60 / 100.1010 minutes; holding bar 2
09:40 to 09:45100.10 / 100.40 / 99.40 / 99.8015 minutes; holding bar 3; request exit
Next bar opens at 09:45Opening price $99.70Default market exit fills at this open

Weekend gaps and fixed session expiry

Assume a five-minute regular session ends Friday at 16:00 and resumes Monday at 09:30, with no holiday or daylight-saving change. A fill on Friday at 15:55 reaches a 12-minute deadline at 16:07, when no bars exist. The example next evaluates at Monday 09:35 and then requests the exit. Under default settings it fills at the next available opening tick, not retroactively on Friday.

  • At Monday 09:35 the elapsed clock reads 3,940 minutes, the completed holding-bar count is two, and the trading-day counter is one. With a three-bar limit, detection instead occurs at Monday 09:40.
  • A fixed exit such as 15:55 America/New_York is a separate policy. Use an explicit session and IANA timezone, and align the intended boundary with chart bars. A fixed UTC offset does not follow daylight-saving changes.
  • On a shortened trading day, the usual 15:55 bar may never occur. Session strings define time windows; they do not supply a complete exchange holiday and early-close calendar.
  • If flat-before-close is required, identify an available earlier decision bar and allow time for execution. Detecting the first bar outside a session can be too late when that bar is the next morning.
  • A time exit cannot protect against a gap while the venue is closed. Keep the price-risk policy, allowed overnight exposure and broker order behavior explicit.

Expire pending entries separately from open positions

An entry request can wait without creating a position. Suppose a $99 buy limit is submitted at 09:30 while every subsequent low stays above $99, and its intended order-age limit is twelve minutes. At 09:45 a close-only script can cancel that still-pending entry ID; there is no filled trade to close and no holding timer to start.

  • Track the submission timestamp separately and cancel the pending entry with strategy.cancel using its entry ID. Disable resubmission after expiry, or the next signal can recreate the expired order.
  • If the 09:40 to 09:45 bar touches $99 at 09:43, a cancellation evaluated at 09:45 is too late. Decide whether to reject entries one bar early, use a finer execution model, or accept and immediately manage such late fills.
  • Do not use strategy.cancel_all casually while another position needs protective exits: it also cancels pending exit orders. A position close and a pending-order cancellation serve different purposes.
  • For a broker-enforced good-till-date order, verify the broker and venue contract separately. A Pine timestamp condition is not a broker expiry instruction.

Verify fills, then preserve the rule in the journal

In TradingView, add the diagnostic to a standard five-minute chart, select a submission time with later bars available, and inspect the Strategy Report trade row alongside the TIME marker and Data Window. Record the symbol, session, timezone, script version, inputs and execution properties. A syntax check alone does not validate this run.

  • For a continuous interval, compare actual entry time, expiry threshold, marker bar close and exit fill with the arithmetic sample. Run Bars = 3 and Minutes = 12 separately, then repeat with the closing-tick option.
  • Repeat across the final session bar, a weekend, a holiday and an overnight session. Also test a timeout beyond the last loaded bar; it can leave a position open rather than produce a completed exit.
  • Ask Pine Script AI Coding Agent to adapt the timer to your existing entries and price protection. Review entry IDs, quantity units, tick distances and exit priority before interpreting performance.
  • In Trading Journal, use plan notes for the clock, maximum duration and initial price risk. Use review notes for the detection time, actual exit, costs and any delay. Label backtests as simulations and retain original risk when comparing R multiples.
  • These Pineify tools support script work and trade records. They do not automatically submit broker orders or determine broker margin requirements.
Where Pineify fits

Pine Script AI Coding Agent

Specify the timer unit, entry-fill anchor and exit timing, then review the generated strategy against individual trade records.

Also useful: Trading Journal. Record planned holding time, initial risk and the actual exit, with notes explaining delays and execution differences.

Draft a time-exit rule

Frequently asked questions

Educational information, not investment advice. The price paths and timing calculations are hypothetical. The diagnostic is not a complete risk-managed strategy. Backtests do not guarantee future returns or live execution.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.