Pine Script Strategy & Order Execution

Pine Script Limit Orders: How to Code and Backtest in TradingView

Pass an absolute price to the limit parameter of strategy.entry() or strategy.order() to create a simulated limit order. A buy limit caps the purchase price; a sell limit sets a minimum sale price. The broker emulator applies order timing and price-verification settings. A touch is not evidence of a live fill, and a limit already favorable to the market can fill on the next available tick without waiting for a pullback.

Build Limit Order Strategies with AI

How limit orders execute in Pine Script strategies

By default, a strategy calculates at bar close and its new order can first fill on the next available tick, usually the next bar open. A buy limit below the current price waits for an eligible price; a buy limit above it is already marketable. Reverse the price relationships for a sell. The emulator does not reconstruct queue priority, order-book depth or partial fills from OHLC bars. Bar Magnifier can add available lower-timeframe price detail, but it does not add a real exchange order book.

Order typeFunction & syntaxExecution conditionFill price characteristics
Market orderstrategy.entry("Long", strategy.long)Next available tick; next bar open under default close-only calculationEmulated fill price plus configured slippage; not guaranteed current close
Limit orderstrategy.entry("Long", strategy.long, limit = 150)Buy price must be 150 or better after order creation and any verification requirementIf eligible and filled, limit price or better; execution is not guaranteed
Stop orderstrategy.entry("Long", strategy.long, stop = 160)Triggers when bar high >= 160Activates a market order at the stop; gaps can worsen the fill
Stop-limit orderstrategy.entry(..., stop = 160, limit = 161)Triggers at stop; caps execution at limitCombines breakout trigger with slippage protection ceiling

Complete Pine Script v6 pullback limit order strategy with expiration timeout

This long-only example places one limit order 1.5% below a breakout close. It is a fixed percentage, not a Fibonacci retracement. Further signals leave the pending price and its original age unchanged. With the default five-bar timeout, cancellation runs at the close of the fifth subsequent bar if the order is still unfilled; a fill earlier on that bar is not undone.

  • The limit is rounded to the symbol tick. Ten percent of equity is position size, not a maximum-loss budget. The 2% stop and 4% target are illustrative and exclude commission and slippage.
  • The bracket is first submitted when a filled position is observed at a later calculation. With default close-only execution, the fill bar can have no active bracket until its close. This example does not claim immediate post-fill protection; inspect this interval before adapting it.
  • Acceptance checks: repeated breakout signals must not move a pending line; an unfilled order placed at bar 10 cancels at bar 15 close; a fill clears the pending line on the next calculation. These are checks to perform on the chart, not reported live tests.
Pine Script v6: Pullback limit order entry with 5-bar cancellation timeoutpinescript
//@version=6
strategy("Pullback Limit Order Strategy [v6]", 
         overlay = true, 
         initial_capital = 10000, 
         default_qty_type = strategy.percent_of_equity, 
         default_qty_value = 10)

// Inputs
breakoutBars = input.int(20, "Breakout Lookback", minval = 2)
pullbackPercent = input.float(1.5, "Pullback Target %", minval = 0.1, maxval = 99)
cancelAfterBars = input.int(5, "Cancel Timeout (Bars)", minval = 1)

// Track recent breakout
recentHigh = ta.highest(high, breakoutBars)[1]
breakoutOccurred = ta.crossover(close, recentHigh)

// Order tracking state
var int orderPlacedBar = na
var float pendingLimitPrice = na

// Reconcile the tracker when a fill becomes visible at this calculation.
if strategy.position_size > 0
    orderPlacedBar := na
    pendingLimitPrice := na

// Cancel at the close of the timeout bar; do not reset age on a new signal.
bool expiredThisBar = not na(orderPlacedBar) and bar_index - orderPlacedBar >= cancelAfterBars
if expiredThisBar and strategy.position_size == 0
    strategy.cancel("PullbackBuy")
    orderPlacedBar := na
    pendingLimitPrice := na

if breakoutOccurred and strategy.position_size == 0 and na(orderPlacedBar) and not expiredThisBar
    pendingLimitPrice := math.round_to_mintick(close * (1 - pullbackPercent / 100))
    orderPlacedBar := bar_index
    strategy.entry("PullbackBuy", strategy.long, limit = pendingLimitPrice)

// Visualize pending limit price
plot(pendingLimitPrice, "Pending Limit Level", color = color.green, style = plot.style_circles)

// Risk management exit for filled positions
if strategy.position_size > 0
    entryPrice = strategy.position_avg_price
    strategy.exit("Exit", from_entry = "PullbackBuy", 
                  stop = entryPrice * 0.98, 
                  limit = entryPrice * 1.04)

TradingView backtesting assumptions for limit orders

When evaluating backtested strategies that use limit orders, understand how TradingViews execution engine models historical price movement:

  • Check order creation before the touched price: an earlier low in the signal bar cannot fill an order submitted at that bar close. A gap across an existing price order can fill at the new bar open rather than the requested level.
  • Backtest fill assumptions: Under Strategy Settings, you can configure "Verify price for limit orders" with an additional tick threshold to ensure price penetrates deeper into the level before registering a fill.
  • Price verification is a hypothetical queue assumption, not measured liquidity. Compare settings and inspect individual fills; neither a clean fill ledger nor syntax success establishes live execution quality.

Best practices: Canceling unfilled limit orders

Define when an unfilled order no longer represents your rule. Use explicit IDs and expiry logic, and inspect the order ledger as well as any plotted pending line. The example is an educational state machine, not an automated live execution service.

  • Always assign explicit order IDs: Use distinct names like "PullbackBuy" so you can invoke strategy.cancel("PullbackBuy") cleanly.
  • Track order age from its original submission. Choose and test a duration as part of your rule; no expiry length is established as profitable here.
  • Clear pending state upon position fill: When strategy.position_size changes from 0 to positive, clear any pending limit trackers.
Where Pineify fits

Pine Script AI Coding Agent

Draft limit-entry and cancellation rules with the AI Coding Agent, then review the source, diagnostics and order timeline in TradingView.

Also useful: Strategy Optimizer. Compare supported strategy input settings on historical data, with separate out-of-sample checks and explicit costs; a fitted setting is not a future optimum.

Build Limit Order Strategies with AI

Frequently asked questions

Educational code, not investment advice or a tested trading strategy. Limit orders constrain price but may remain unfilled. OHLC-based simulation does not establish actual liquidity, queue priority or broker execution.

Sources and verification