Indicator · Pine Script v5 · On the chart

NY Anchor Range FVG Breakout

by riegodavid-git· code credited to david.riego.01@gmail.com

An overlay indicator that marks an anchor range during a configurable morning session, by default 09:00 to 10:00 New York time.

View on GitHub

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code445
Settings11inputs
LicenceNone statedfile: MPL-2.0
Last update4 months ago25 Jun 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

445 lines of Pine Script v5 from pinescript/strategies/ny_anchor_fvg_breakout.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

ny_anchor_fvg_breakout.pine
// This source code is subject to the terms of the Mozilla Public License 2.0
// © david.riego.01@gmail.com
//@version=5
indicator("NY Anchor Range FVG Breakout", overlay=true,
  max_boxes_count=100, max_lines_count=200, max_labels_count=200)

// ═══════════════════════════════════════════════════════════════════════════════
//  INPUTS
// ═══════════════════════════════════════════════════════════════════════════════

i_tz             = input.string("America/New_York", "Timezone",
                     group="Anchor Session")
i_session        = input.string("0900-1000",        "Session Window (HHMM-HHMM)",
                     group="Anchor Session")

i_breakoutLegLen = input.int(10, "Breakout Leg Length (bars)",
                     minval=3, maxval=50, group="FVG Settings",
                     tooltip="Number of bars after breakout considered part of the breakout leg (Tier 2 FVGs).")

i_swingLen       = input.int(5, "Swing Lookback",
                     minval=2, maxval=20, group="BOS Settings",
                     tooltip="Left and right bar count for pivot high/low confirmation.")
i_bosLimit       = input.int(3, "BOS Cancel Count",
                     minval=1, maxval=5, group="BOS Settings",
                     tooltip="Cancel limit order after this many with-bias breaks of structure.")

i_rrRatio        = input.float(1.0, "R:R Ratio",
                     minval=0.5, maxval=5.0, step=0.5, group="Risk")

i_showAnchorBox  = input.bool(true,  "Show Anchor Box",       group="Display")
i_showFVGBoxes   = input.bool(true,  "Show FVG Zones",        group="Display")
i_showBOSLabels  = input.bool(true,  "Show BOS Labels",       group="Display")
i_showTradeLines = input.bool(true,  "Show Trade Lines",      group="Display")
i_deleteOld      = input.bool(true,  "Clean Up Prior Day",    group="Display")

// ═══════════════════════════════════════════════════════════════════════════════
//  STATE  (var = persists across bars; reset manually on new day)
// ═══════════════════════════════════════════════════════════════════════════════

// ── Anchor range ─────────────────────────────────────────────────────────────
var float anchorHigh   = na
var float anchorLow    = na
var bool  anchorLocked = false
var int   anchorLeft   = na
var box   anchorBox    = na

// ── Bias / breakout ───────────────────────────────────────────────────────────
var int   bias         = 0        // 0=none  1=bullish  -1=bearish
var bool  breakoutDone = false
var int   breakoutBar  = na

// ── FVG storage (parallel arrays; one element per detected FVG) ───────────────
var float[] fvgTop    = array.new_float(0)   // upper bound of gap
var float[] fvgBot    = array.new_float(0)   // lower bound of gap
var float[] fvgEntry  = array.new_float(0)   // limit price (near edge)
var float[] fvgSL     = array.new_float(0)   // raw SL level (before mintick offset)
var int[]   fvgTier   = array.new_int(0)     // 1=overlaps anchor  2=breakout leg  3=other
var int[]   fvgDir    = array.new_int(0)     // 1=bullish  -1=bearish
var box[]   fvgBoxes  = array.new_box(0)

// ── Active / selected FVG ─────────────────────────────────────────────────────
var int   activeFVG   = -1

// ── Trade levels & lines ──────────────────────────────────────────────────────
var float entryPrice  = na
var float stopPrice   = na
var float tpPrice     = na
var line  entryLine   = na
var line  slLine      = na
var line  tpLine      = na

// ── Trade lifecycle ───────────────────────────────────────────────────────────
var bool  inTrade        = false
var bool  orderCancelled = false

// ── BOS tracking ─────────────────────────────────────────────────────────────
var int   bosCount     = 0
var float lastPivotRef = na   // last confirmed swing level in bias direction

// ═══════════════════════════════════════════════════════════════════════════════
//  DAILY RESET
// ═══════════════════════════════════════════════════════════════════════════════

isNewDay = ta.change(time("D")) != 0

if isNewDay
    // Delete prior-day drawing objects
    if i_deleteOld
        box.delete(anchorBox)
        line.delete(entryLine)
        line.delete(slLine)
        line.delete(tpLine)
        int _fvgN = array.size(fvgBoxes)
        if _fvgN > 0
            for i = _fvgN - 1 to 0
                box.delete(array.get(fvgBoxes, i))

    anchorBox      := na
    anchorHigh     := na
    anchorLow      := na
    anchorLocked   := false
    anchorLeft     := na
    bias           := 0
    breakoutDone   := false
    breakoutBar    := na
    activeFVG      := -1
    entryPrice     := na
    stopPrice      := na
    tpPrice        := na
    entryLine      := na
    slLine         := na
    tpLine         := na
    inTrade        := false
    orderCancelled := false
    bosCount       := 0
    lastPivotRef   := na
    array.clear(fvgTop)
    array.clear(fvgBot)
    array.clear(fvgEntry)
    array.clear(fvgSL)
    array.clear(fvgTier)
    array.clear(fvgDir)
    array.clear(fvgBoxes)

// ═══════════════════════════════════════════════════════════════════════════════
//  PHASE 1 — ANCHOR RANGE  (9:00–10:00 AM New York)
// ═══════════════════════════════════════════════════════════════════════════════

inAnchorSession  = not na(time(timeframe.period, i_session, i_tz))
prevInSession    = not na(time(timeframe.period, i_session, i_tz)[1])
anchorJustClosed = prevInSession and not inAnchorSession and not anchorLocked

if inAnchorSession and not anchorLocked
    if na(anchorHigh)
        anchorHigh := high
        anchorLow  := low
        anchorLeft := bar_index
    else
        anchorHigh := math.max(anchorHigh, high)
        anchorLow  := math.min(anchorLow,  low)

if anchorJustClosed
    anchorLocked := true
    if i_showAnchorBox
        anchorBox := box.new(
          left         = anchorLeft,
          top          = anchorHigh,
          right        = bar_index + 500,
          bottom       = anchorLow,
          border_color = color.new(color.yellow, 0),
          bgcolor      = color.new(color.yellow, 85),
          border_width = 1)

// ═══════════════════════════════════════════════════════════════════════════════
//  PHASE 2 — BREAKOUT  (candle close outside anchor range)
// ═══════════════════════════════════════════════════════════════════════════════

if barstate.isconfirmed and anchorLocked and not breakoutDone
    if close > anchorHigh
        bias         := 1
        breakoutDone := true
        breakoutBar  := bar_index
        label.new(bar_index, high,
          text="▲ BO", style=label.style_label_down,
          color=color.new(color.teal, 0), textcolor=color.white, size=size.small)
    else if close < anchorLow
        bias         := -1
        breakoutDone := true
        breakoutBar  := bar_index
        label.new(bar_index, low,
          text="▼ BO", style=label.style_label_up,
          color=color.new(color.maroon, 0), textcolor=color.white, size=size.small)

// ═══════════════════════════════════════════════════════════════════════════════
//  PHASE 3 — FVG DETECTION  (runs every confirmed bar after breakout)
// ═══════════════════════════════════════════════════════════════════════════════

newFVGDetected = false

if barstate.isconfirmed and breakoutDone and not inTrade and not orderCancelled
    // 3-candle FVG pattern — all 3 candles must be at or after the breakout bar
    bullFVG = bias == 1  and high[2] < low[0] and (bar_index - 2) >= breakoutBar
    bearFVG = bias == -1 and low[2] > high[0]  and (bar_index - 2) >= breakoutBar

    if bullFVG or bearFVG
        // Gap boundaries
        gTop  = bullFVG ? low[0]  : low[2]    // upper edge
        gBot  = bullFVG ? high[2] : high[0]   // lower edge

        // Limit entry at near edge (top for longs, bottom for shorts)
        ePrice = bullFVG ? gTop : gBot

        // SL: one tick beyond the first (oldest) candle of the FVG pattern
        // First candle = candle[2] (bar_index - 2)
        slRaw = bullFVG ? low[2] - syminfo.mintick : high[2] + syminfo.mintick

        // ── Priority tier ──────────────────────────────────────────────────
        // Tier 1: FVG zone contains the anchor boundary level
        overlapsAnchor = bullFVG
          ? (gBot <= anchorHigh and gTop >= anchorHigh)
          : (gBot <= anchorLow  and gTop >= anchorLow)

        // Tier 2: middle candle of FVG formed within the breakout leg
        onBreakoutLeg = bar_index[1] <= breakoutBar + i_breakoutLegLen

        tier = overlapsAnchor ? 1 : onBreakoutLeg ? 2 : 3

        // ── Store FVG ──────────────────────────────────────────────────────
        array.push(fvgTop,   gTop)
        array.push(fvgBot,   gBot)
        array.push(fvgEntry, ePrice)
        array.push(fvgSL,    slRaw)
        array.push(fvgTier,  tier)
        array.push(fvgDir,   bias)

        // ── Draw FVG box (dim by default; selected one will be brightened) ─
        fvgBorderCol = bullFVG ? color.new(color.aqua, 50)   : color.new(color.orange, 50)
        fvgBGCol     = bullFVG ? color.new(color.aqua, 90)   : color.new(color.orange, 90)
        if i_showFVGBoxes
            newBox = box.new(
              left=bar_index - 2, top=gTop, right=bar_index + 100, bottom=gBot,
              border_color=fvgBorderCol, bgcolor=fvgBGCol, border_width=1)
            array.push(fvgBoxes, newBox)
        else
            array.push(fvgBoxes, na)

        newFVGDetected := true

// ═══════════════════════════════════════════════════════════════════════════════
//  FVG SELECTION  (re-evaluates every time a new FVG is detected)
//  Priority: lowest tier wins; ties broken by distance to anchor boundary
// ═══════════════════════════════════════════════════════════════════════════════

if newFVGDetected and not inTrade and not orderCancelled
    n       = array.size(fvgTop)
    bestIdx  = -1
    bestTier = 99
    bestDist = 1e10

    for i = 0 to n - 1
        t   = array.get(fvgTier, i)
        mid = (array.get(fvgTop, i) + array.get(fvgBot, i)) / 2.0
        d   = bias == 1 ? math.abs(mid - anchorHigh) : math.abs(mid - anchorLow)
        if t < bestTier or (t == bestTier and d < bestDist)
            bestIdx  := i
            bestTier := t
            bestDist := d

    if bestIdx >= 0 and bestIdx != activeFVG
        isUpgrade = activeFVG >= 0   // true when replacing a prior active FVG

        // ── Dim the previously active FVG box ─────────────────────────────
        if activeFVG >= 0 and i_showFVGBoxes
            prevBox = array.get(fvgBoxes, activeFVG)
            if not na(prevBox)
                box.set_border_color(prevBox,
                  bias == 1 ? color.new(color.aqua, 50)   : color.new(color.orange, 50))
                box.set_bgcolor(prevBox,
                  bias == 1 ? color.new(color.aqua, 90)   : color.new(color.orange, 90))
                box.set_border_width(prevBox, 1)

        activeFVG := bestIdx

        // ── Highlight the new active FVG box ──────────────────────────────
        if i_showFVGBoxes
            newActiveBox = array.get(fvgBoxes, bestIdx)
            if not na(newActiveBox)
                box.set_border_color(newActiveBox,
                  bias == 1 ? color.new(color.aqua, 0) : color.new(color.orange, 0))
                box.set_bgcolor(newActiveBox,
                  bias == 1 ? color.new(color.aqua, 55) : color.new(color.orange, 55))
                box.set_border_width(newActiveBox, 2)

        // ── Delete old entry/SL/TP lines ──────────────────────────────────
        line.delete(entryLine)
        line.delete(slLine)
        line.delete(tpLine)

        // ── Calculate trade levels ─────────────────────────────────────────
        entryPrice := array.get(fvgEntry, bestIdx)
        stopPrice  := array.get(fvgSL,    bestIdx)
        riskAmt     = math.abs(entryPrice - stopPrice)
        tpPrice    := bias == 1
          ? entryPrice + riskAmt * i_rrRatio
          : entryPrice - riskAmt * i_rrRatio

        // ── Draw new trade lines ──────────────────────────────────────────
        if i_showTradeLines
            entryLine := line.new(bar_index, entryPrice, bar_index + 100, entryPrice,
              color=color.new(color.white, 0), style=line.style_dashed, width=1)
            slLine := line.new(bar_index, stopPrice, bar_index + 100, stopPrice,
              color=color.new(color.red, 0), style=line.style_solid, width=1)
            tpLine := line.new(bar_index, tpPrice, bar_index + 100, tpPrice,
              color=color.new(color.lime, 0), style=line.style_solid, width=1)
            // Tier label next to entry line
            tierTxt = bestTier == 1 ? "T1" : bestTier == 2 ? "T2" : "T3"
            dirTxt  = bias == 1 ? "LONG" : "SHORT"
            label.new(bar_index, entryPrice,
              text=dirTxt + " " + tierTxt + "\nE: " + str.tostring(entryPrice, format.mintick) +
                   "\nSL: " + str.tostring(stopPrice, format.mintick) +
                   "\nTP: " + str.tostring(tpPrice, format.mintick),
              style=bias == 1 ? label.style_label_upper_left : label.style_label_lower_left,
              color=color.new(bias == 1 ? color.teal : color.maroon, 10),
              textcolor=color.white, size=size.small)

        alert(
          "NY FVG Limit " + (isUpgrade ? "UPGRADED" : "SET") +
          " | " + (bias == 1 ? "LONG" : "SHORT") +
          " | Tier " + str.tostring(bestTier) +
          " | Entry: "  + str.tostring(entryPrice, format.mintick) +
          " | SL: "     + str.tostring(stopPrice,  format.mintick) +
          " | TP: "     + str.tostring(tpPrice,    format.mintick),
          alert.freq_once_per_bar)

// ═══════════════════════════════════════════════════════════════════════════════
//  EXTEND TRADE LINES & FVG BOXES  (keep them reaching forward each bar)
// ═══════════════════════════════════════════════════════════════════════════════

if not na(entryLine) and not inTrade and not orderCancelled
    line.set_x2(entryLine, bar_index + 100)
    line.set_x2(slLine,    bar_index + 100)
    line.set_x2(tpLine,    bar_index + 100)

if i_showFVGBoxes and breakoutDone and not inTrade
    int _n = array.size(fvgBoxes)
    if _n > 0
        for i = 0 to _n - 1
            b = array.get(fvgBoxes, i)
            if not na(b)
                box.set_right(b, bar_index + 100)

// ═══════════════════════════════════════════════════════════════════════════════
//  PHASE 4 — BOS DETECTION
//  Counts with-bias structure breaks (higher highs for bullish, lower lows for bearish)
//  Cancel limit order once bosCount >= i_bosLimit
// ═══════════════════════════════════════════════════════════════════════════════

if barstate.isconfirmed and breakoutDone and not inTrade and not orderCancelled
    ph = ta.pivothigh(i_swingLen, i_swingLen)
    pl = ta.pivotlow(i_swingLen,  i_swingLen)

    // Pivot occurred i_swingLen bars ago
    pivotBar = bar_index - i_swingLen

    if bias == 1 and not na(ph) and pivotBar >= breakoutBar
        if na(lastPivotRef)
            // First swing high after breakout — set reference, no count yet
            lastPivotRef := ph
        else if ph > lastPivotRef
            // Price broke above the previous swing high → BOS in bias direction
            bosCount     += 1
            lastPivotRef := ph
            if i_showBOSLabels
                label.new(pivotBar, ph,
                  text="HH " + str.tostring(bosCount),
                  xloc=xloc.bar_index, style=label.style_label_down,
                  color=color.new(color.purple, 0), textcolor=color.white, size=size.small)

    if bias == -1 and not na(pl) and pivotBar >= breakoutBar
        if na(lastPivotRef)
            lastPivotRef := pl
        else if pl < lastPivotRef
            bosCount     += 1
            lastPivotRef := pl
            if i_showBOSLabels
                label.new(pivotBar, pl,
                  text="LL " + str.tostring(bosCount),
                  xloc=xloc.bar_index, style=label.style_label_up,
                  color=color.new(color.purple, 0), textcolor=color.white, size=size.small)

    if bosCount >= i_bosLimit
        orderCancelled := true

        // Grey out lines
        if not na(entryLine)
            line.set_color(entryLine, color.new(color.gray, 60))
            line.set_color(slLine,    color.new(color.gray, 60))
            line.set_color(tpLine,    color.new(color.gray, 60))

        // Cancellation label
        label.new(bar_index,
          bias == 1 ? low - syminfo.mintick * 8 : high + syminfo.mintick * 8,
          text="CANCELLED\n(" + str.tostring(i_bosLimit) + " BOS)",
          style=bias == 1 ? label.style_label_up : label.style_label_down,
          color=color.new(color.red, 0), textcolor=color.white, size=size.normal)

        alert("NY FVG Order CANCELLED — " + str.tostring(i_bosLimit) +
              " BOS reached | " + syminfo.ticker,
              alert.freq_once_per_bar)

// ═══════════════════════════════════════════════════════════════════════════════
//  PHASE 5 — TRADE SIMULATION  (limit fill + SL/TP check)
// ═══════════════════════════════════════════════════════════════════════════════

if barstate.isconfirmed and not na(entryPrice) and not inTrade and not orderCancelled
    filled = (bias == 1 and low <= entryPrice) or (bias == -1 and high >= entryPrice)
    if filled
        inTrade := true
        alert(
          "NY FVG ENTRY FILLED | " + (bias == 1 ? "LONG" : "SHORT") +
          " @ " + str.tostring(entryPrice, format.mintick) +
          " | SL: " + str.tostring(stopPrice, format.mintick) +
          " | TP: "  + str.tostring(tpPrice,  format.mintick),
          alert.freq_once_per_bar)

if barstate.isconfirmed and inTrade
    slHit = (bias == 1 and low  <= stopPrice) or (bias == -1 and high >= stopPrice)
    tpHit = (bias == 1 and high >= tpPrice)   or (bias == -1 and low  <= tpPrice)

    if slHit or tpHit
        inTrade := false

        resultTxt = tpHit ? "TP ✓" : "SL ✗"
        resultClr = tpHit ? color.new(color.lime, 0) : color.new(color.red, 0)
        resultY   = tpHit ? tpPrice : stopPrice

        // Extend lines to exit bar
        if not na(entryLine)
            line.set_x2(entryLine, bar_index)
            line.set_x2(slLine,    bar_index)
            line.set_x2(tpLine,    bar_index)

        label.new(bar_index, resultY,
          text=resultTxt,
          style=label.style_label_left,
          color=resultClr, textcolor=color.white, size=size.normal)

// ═══════════════════════════════════════════════════════════════════════════════
//  ALERT CONDITIONS  (for TradingView alert manager)
// ═══════════════════════════════════════════════════════════════════════════════

alertcondition(
  not na(entryPrice) and na(entryPrice[1]) and not orderCancelled,
  title   = "NY FVG — Limit Order Set",
  message = "NY Anchor FVG: New limit order set on {{ticker}} | {{interval}}")

alertcondition(
  inTrade and not inTrade[1],
  title   = "NY FVG — Entry Filled",
  message = "NY Anchor FVG: Entry filled on {{ticker}}")

alertcondition(
  orderCancelled and not orderCancelled[1],
  title   = "NY FVG — Order Cancelled",
  message = "NY Anchor FVG: Order cancelled ({{interval}} {{ticker}})")

Overview

NY Anchor Range FVG Breakout detects a breakout from that range, sets a bullish or bearish bias, and finds fair value gaps in the breakout leg. It then tracks breaks of structure using swing pivots and draws planned trade lines with a chosen reward-to-risk ratio, cancelling the limit idea after a set number of breaks. Boxes, labels and lines can be toggled and cleared each day. It draws levels only and places no orders.

Details

Published by

riegodavid-git on GitHub

Code credit

david.riego.01@gmail.com, as written in the script's header

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

SMC / ICT / price action, Breakout, Sessions & time

Markets

Any symbol

Timeframes

M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
TimezonestringAmerica/New_Yorki_tz
Session Window (HHMM-HHMM)string0900-1000i_session
Breakout Leg Length (bars)int10i_breakoutLegLen
Swing Lookbackint5i_swingLen
BOS Cancel Countint3i_bosLimit
R:R Ratiofloat1.0i_rrRatio
Show Anchor Boxbooltruei_showAnchorBox
Show FVG Zonesbooltruei_showFVGBoxes
Show BOS Labelsbooltruei_showBOSLabels
Show Trade Linesbooltruei_showTradeLines
Clean Up Prior Daybooltruei_deleteOld
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

SMC Strategy Hub + Alerts

by eddiebelaval
7 stars

This indicator marks market structure shifts when price closes beyond the prior lookback high or low, then labels a buy or sell with an ATR-based stop and a take-profit distance set by the TP multiplier. Optional boxes highlight bullish and bearish fair value

Indicator v5 SMC / ICT / price actionBreakout
Updated 3 months ago · None stated GitHub repository of SMC Strategy Hub + Alerts

Advanced ORB + ICT System

by alboogycOdR
6 stars

Advanced ORB + ICT System plots Opening Range Breakout (ORB) levels alongside Inner Circle Trader (ICT) concepts directly on the price chart. It highlights ORB boxes, Fair Value Gaps (FVGs), Order Blocks, liquidity grabs, and key support and resistance levels

Indicator v5 SMC / ICT / price actionBreakout
Updated 7 months ago · None stated GitHub repository of Advanced ORB + ICT System

CH033 ORB+ VWAPs Indicator

by sandovalchristian033
1 stars

This indicator plots multiple anchored VWAPs, session ranges, fair value gaps, and multi-instrument monitoring tables directly on the price chart. It signals long or short setups when price breaks the initial fifteen-minute New York opening range, re-enters th

Indicator v6 BreakoutSessions & time
Updated 2 months ago · None stated GitHub repository of CH033 ORB+ VWAPs Indicator

ORB + ICT Manual Signals v3

by mccallister-dev
1 stars

This overlay indicator marks opening-range breakouts inside configurable Asian, London, and New York session windows. It searches for a break, retest, and continuation after an optional delay, then shows confirmed-bar signals with estimated entry, stop, and ta

Indicator v6 BreakoutSMC / ICT / price action
Updated 5 weeks ago · None stated GitHub repository of ORB + ICT Manual Signals v3

SMC Entry Filter

by andriiops
1 stars

This overlay indicator tracks confirmed swing highs and lows as liquidity levels and marks a break of structure when the close moves beyond the last swing. It detects bullish and bearish fair value gaps that meet a minimum ATR size, then plots filtered long an

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · MIT GitHub repository of SMC Entry Filter

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers