Indicator · Pine Script v6 · On the chart

Golden Pocket Zones

by MeridianAlgo

Golden Pocket Zones draws fixed-height Fibonacci zones on the price chart.

View on GitHub

GitHub stars9on the repository
Pine versionv6current
Lines of code321
Settings6inputs
LicenceMIT
Last update4 months ago29 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

321 lines of Pine Script v6 from examples/Golden_Pocket_Zones.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

Golden_Pocket_Zones.pine
//@version=6
indicator("Golden Pocket Zones", overlay=true, max_boxes_count=500)

// ========================================
// INPUT SETTINGS
// ========================================
lookbackDays = input.int(20, "Lookback Days", minval=1, maxval=100, tooltip="Number of daily candles to analyze for golden pocket zones")
zoneHeightPct = input.float(3.0, "Zone Height (% of ADR10)", minval=0.1, maxval=50.0, step=0.1, tooltip="Height of golden pocket zone as percentage of ADR10 - SAME for all zones")
minCandleSizePct = input.float(60.0, "Min Candle Size (% of ADR10)", minval=0, maxval=200, step=5, tooltip="Only show zones for candles larger than this % of ADR10. Set to 0 to show all zones.")
showLabels = input.bool(true, "Show Labels", tooltip="Display age and strength labels inside zones")

// ========================================
// COLOR SETTINGS
// ========================================
zoneColor = input.color(color.new(#FFB84D, 20), "Zone Color", tooltip="Color of the golden pocket zones")
textColor = input.color(color.new(#000000, 0), "Text Color", tooltip="Color of the text labels")

// ========================================
// ZONE DATA TYPE
// ========================================
type ZoneData
    float upper
    float lower
    int startBar
    int age
    float strength

// ========================================
// FETCH DAILY DATA USING REQUEST.SECURITY
// ========================================
// Request daily OHLC and time data
[dailyHigh, dailyLow, dailyTime] = request.security(syminfo.tickerid, "D", [high, low, time], lookahead=barmerge.lookahead_off)

// Calculate ADR10 (10-period average daily range) on daily timeframe
adr10 = request.security(syminfo.tickerid, "D", ta.sma(high - low, 10), lookahead=barmerge.lookahead_off)

// ========================================
// STORAGE ARRAYS
// ========================================
var int lastDailyTime = 0
var int lastDailyStartBar = na
var array<float> dailyHighs = array.new<float>()
var array<float> dailyLows = array.new<float>()
var array<int> dailyBars = array.new<int>()
var array<float> dailyADRs = array.new<float>()
var array<ZoneData> zones = array.new<ZoneData>()

// Store the current ADR10 for consistent zone heights
var float currentADR10 = na

// ========================================
// HELPER FUNCTIONS
// ========================================

// Get pip size for current instrument
f_getPips() =>
    syminfo.type == "forex" ? (syminfo.currency == "JPY" ? 0.01 : 0.0001) : (syminfo.ticker == "XAUUSD" or syminfo.ticker == "GOLD") ? 0.01 : 0.0001

// Convert price distance to pips
f_toPips(val) =>
    math.abs(val) / f_getPips()

// Calculate golden pocket zone boundaries with FIXED zone height
calcGoldenPocket(float high, float low, float fixedZoneHeight) =>
    candleRange = high - low
    
    // Golden pocket is between 50% and 61.8% Fibonacci retracement
    // Calculate midpoint at 55.9% (average of 0.5 and 0.618)
    gpMid = low + candleRange * 0.559
    
    // Use the SAME fixed zone height for all zones
    [gpMid + fixedZoneHeight, gpMid - fixedZoneHeight, candleRange]

// Check if two zones overlap
zonesOverlap(float upper1, float lower1, float upper2, float lower2) =>
    not (upper1 < lower2 or upper2 < lower1)

// Merge two zones and return new boundaries
mergeZones(float upper1, float lower1, float upper2, float lower2) =>
    [math.max(upper1, upper2), math.min(lower1, lower2)]

// Calculate strength rating (4-10 scale)
calcStrength(float candleSize, float adr) =>
    strengthPct = (candleSize / adr) * 100.0
    strength = 0.0
    if strengthPct >= 160
        strength := 10.0
    else if strengthPct >= 140
        strength := 9.0
    else if strengthPct >= 120
        strength := 8.0
    else if strengthPct >= 100
        strength := 7.0
    else if strengthPct >= 80
        strength := 6.0
    else if strengthPct >= 60
        strength := 5.0
    else
        strength := 4.0
    strength

// ========================================
// MAIN LOGIC - DETECT NEW DAILY BAR
// ========================================
if dailyTime != lastDailyTime and not na(dailyTime)
    lastDailyTime := dailyTime
    
    // Update current ADR10 for consistent zone heights
    if not na(adr10) and adr10 > 0
        currentADR10 := adr10
    
    // Store the START bar of the PREVIOUS daily candle (if exists)
    if not na(lastDailyStartBar)
        array.unshift(dailyBars, lastDailyStartBar)
    
    // Record the START bar of the NEW daily candle
    lastDailyStartBar := bar_index
    
    // Store daily data at the beginning of arrays
    array.unshift(dailyHighs, dailyHigh)
    array.unshift(dailyLows, dailyLow)
    array.unshift(dailyADRs, adr10)
    
    // Limit array size to lookback period
    if array.size(dailyHighs) > lookbackDays
        array.pop(dailyHighs)
        array.pop(dailyLows)
        array.pop(dailyBars)
        array.pop(dailyADRs)
    
    // Recalculate all zones
    array.clear(zones)
    
    // Calculate FIXED zone height based on current ADR10
    float fixedZoneHeight = not na(currentADR10) ? (currentADR10 * (zoneHeightPct / 100.0) / 2.0) : 0.0
    
    // Build temporary zones array
    tempZones = array.new<ZoneData>()
    
    // Only process if we have data and valid zone height
    int arraySize = array.size(dailyHighs)
    int barsArraySize = array.size(dailyBars)
    if arraySize > 0 and fixedZoneHeight > 0
        for i = 0 to arraySize - 1
            dayHigh = array.get(dailyHighs, i)
            dayLow = array.get(dailyLows, i)
            // Use the stored start bar if available, otherwise use current bar_index
            dayBar = i < barsArraySize ? array.get(dailyBars, i) : bar_index
            dayADR = array.get(dailyADRs, i)
            
            if not na(dayHigh) and not na(dayLow) and not na(dayADR) and dayADR > 0
                candleSize = dayHigh - dayLow
                candleSizePct = (candleSize / dayADR) * 100.0
                
                // Filter by minimum candle size
                if candleSizePct >= minCandleSizePct
                    // Use FIXED zone height for all zones
                    [upper, lower, range] = calcGoldenPocket(dayHigh, dayLow, fixedZoneHeight)
                    
                    // Calculate strength
                    strength = calcStrength(candleSize, dayADR)
                    
                    // Create zone
                    newZone = ZoneData.new(upper, lower, dayBar, i, strength)
                    array.push(tempZones, newZone)
        
        // Merge overlapping zones
        int tempZonesSize = array.size(tempZones)
        if tempZonesSize > 0
            mergedIndices = array.new<bool>()
            for i = 0 to tempZonesSize - 1
                array.push(mergedIndices, false)
            
            for i = 0 to tempZonesSize - 1
                if not array.get(mergedIndices, i)
                    zone1 = array.get(tempZones, i)
                    
                    // Only loop if there are more zones to check
                    if i + 1 < tempZonesSize
                        for j = i + 1 to tempZonesSize - 1
                            if not array.get(mergedIndices, j)
                                zone2 = array.get(tempZones, j)
                                
                                if zonesOverlap(zone1.upper, zone1.lower, zone2.upper, zone2.lower)
                                    // Merge zones
                                    [mergedUpper, mergedLower] = mergeZones(zone1.upper, zone1.lower, zone2.upper, zone2.lower)
                                    zone1.upper := mergedUpper
                                    zone1.lower := mergedLower
                                    // Keep the older age (higher index) and max strength
                                    zone1.age := math.max(zone1.age, zone2.age)
                                    zone1.strength := math.max(zone1.strength, zone2.strength)
                                    // Use the earliest start bar when merging
                                    zone1.startBar := math.min(zone1.startBar, zone2.startBar)
                                    // Mark zone2 as merged
                                    array.set(mergedIndices, j, true)
                    
                    // Add non-merged zone to final zones
                    array.push(zones, zone1)

// ========================================
// DRAW ZONES ON LAST BAR
// ========================================
if barstate.islast and array.size(zones) > 0
    // Clear all existing boxes and labels
    if array.size(box.all) > 0
        for existingBox in box.all
            box.delete(existingBox)
    if array.size(label.all) > 0
        for existingLabel in label.all
            label.delete(existingLabel)
    
    // First pass: calculate all distances to find min/max for heatmap scaling
    minDist = 999999.0
    maxDist = 0.0
    for i = 0 to array.size(zones) - 1
        zone = array.get(zones, i)
        if not na(zone)
            distanceInPrice = 0.0
            if close > zone.upper
                distanceInPrice := close - zone.upper
            else if close < zone.lower
                distanceInPrice := zone.lower - close
            else
                distToUpper = zone.upper - close
                distToLower = close - zone.lower
                distanceInPrice := math.min(distToUpper, distToLower)
            
            pipSize = syminfo.type == "forex" ? (syminfo.currency == "JPY" ? 0.01 : 0.0001) : 0.01
            distancePips = distanceInPrice / pipSize
            minDist := math.min(minDist, distancePips)
            maxDist := math.max(maxDist, distancePips)
    
    // Draw zones from oldest to newest (so newer zones layer on top)
    for i = array.size(zones) - 1 to 0
        zone = array.get(zones, i)
        
        if not na(zone)
            // Calculate distance for this zone
            distanceInPrice = 0.0
            if close > zone.upper
                distanceInPrice := close - zone.upper
            else if close < zone.lower
                distanceInPrice := zone.lower - close
            else
                distToUpper = zone.upper - close
                distToLower = close - zone.lower
                distanceInPrice := math.min(distToUpper, distToLower)
            
            pipSize = syminfo.type == "forex" ? (syminfo.currency == "JPY" ? 0.01 : 0.0001) : 0.01
            distancePips = distanceInPrice / pipSize
            
            // Calculate heatmap color: closer = hotter (orange), farther = colder (yellow)
            // Normalize distance to 0-1 range
            normalizedDist = maxDist > minDist ? (distancePips - minDist) / (maxDist - minDist) : 0.5
            
            // Create color gradient: close = vibrant orange (#FF8C00), far = bright yellow (#FFD700)
            // Far zones (cold): Bright Yellow RGB(255, 215, 0)
            // Close zones (hot): Vibrant Orange RGB(255, 140, 0)
            
            // Linear interpolation
            r = 255
            g = math.round(215 - (215 - 140) * normalizedDist)
            b = math.round(0)
            
            heatmapColor = color.new(color.rgb(r, g, b), 20)
            
            // Create box extending to the right with heatmap color
            // Ensure startBar is within valid range to prevent buffer overflow
            // Use a conservative limit based on available bars
            maxLookback = math.min(2000, bar_index)
            safeStartBar = math.max(zone.startBar, bar_index - maxLookback)
            boxId = box.new(
                 left=safeStartBar,
                 top=zone.upper,
                 right=bar_index + 50,
                 bottom=zone.lower,
                 border_color=color.new(heatmapColor, 70),
                 border_width=1,
                 bgcolor=heatmapColor,
                 extend=extend.right
             )
            
            // Add label 25 bars to the right of current bar
            if showLabels
                ageText = zone.age == 0 ? "TODAY" : str.tostring(zone.age) + " DAYS"
                strengthText = str.tostring(zone.strength, "#") + "/10"
                
                // Calculate distance in pips from current close to nearest zone edge
                distanceInPrice = 0.0
                if close > zone.upper
                    // Price is above zone
                    distanceInPrice := close - zone.upper
                else if close < zone.lower
                    // Price is below zone
                    distanceInPrice := zone.lower - close
                else
                    // Price is inside zone - distance to nearest edge
                    distToUpper = zone.upper - close
                    distToLower = close - zone.lower
                    distanceInPrice := math.min(distToUpper, distToLower)
                
                // Direct pip calculation based on instrument
                pipSize = syminfo.type == "forex" ? (syminfo.currency == "JPY" ? 0.01 : 0.0001) : 0.01
                distancePips = distanceInPrice / pipSize
                distanceText = str.tostring(math.round(distancePips)) + " PIPS"
                labelText = "GOLDEN POCKET ||| AGE " + ageText + " ||| STRENGTH " + strengthText + " ||| DISTANCE " + distanceText
                
                // Calculate midpoint of zone for label Y position
                labelY = (zone.upper + zone.lower) / 2.0
                
                // Create label 25 bars to the right
                label.new(
                     x=bar_index + 25,
                     y=labelY,
                     text=labelText,
                     color=color.new(color.black, 100),
                     textcolor=textColor,
                     size=size.large,
                     style=label.style_label_center,
                     xloc=xloc.bar_index
                 )

Overview

Golden Pocket Zones reads daily highs, lows, and a 10-day average range, then centers a band on the midpoint of the 50 percent and 61.8 percent retracement of each qualifying daily candle. Lookback length, zone height as a percent of that range, and a minimum candle-size filter decide which zones appear. Overlapping zones are merged. Optional labels show age and a strength rating. It does not place trades.

Details

Published by

MeridianAlgo on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Support & resistance

Markets

Forex, Gold

Timeframes

Any timeframe

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.

Topics

code-converterconverterjavascriptpinescripttranspilercode-reviewmeridianalgocode-conversionpinescript-algorithms

Settings

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

SettingTypeDefaultVariable
Lookback Daysint20lookbackDays
Zone Height (% of ADR10)float3.0zoneHeightPct
Min Candle Size (% of ADR10)float60.0minCandleSizePct
Show LabelsbooltrueshowLabels
Zone Colorcolorcolor.new(#FFB84D, 20)zoneColor
Text Colorcolorcolor.new(#000000, 0)textColor
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

948 stars

Moving Average Channel plots separate simple moving averages for upper and lower bands on the price chart. It fills the space between bands with semi-transparent color and colors bars green above the upper band, red below the lower band, or gray in between. Us

Indicator v4 Moving averagesSupport & resistance
Updated 10 days ago · GPL-3.0 GitHub repository of Moving Average Channel

ICT Equal Highs and Lows

by ArunKBhaskar
575 stars

This overlay indicator finds pivot highs and lows on the price chart and compares the last two highs and the last two lows. When the percentage difference between a pair is below the Equal HL threshold, it treats them as equal levels and draws a box. Left and

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows
330 stars

This indicator monitors multiple cryptocurrency symbols for trading signals. It calculates and plots entry prices, take profit, and stop loss levels for each symbol including BTCUSDT, ETHUSDT, BNBUSDT and others. Price crossovers trigger buy, sell or close ale

Indicator v5 Support & resistanceScreeners & dashboards
Updated 2 months ago · None stated GitHub repository of Multi Alert Long/Short [Alorse]

This overlay indicator draws a fixed-range volume profile on the price chart, splitting traded activity into up and down volume at each price level. It also plots a sentiment profile, a developing point of control, and value-area high and low around a configur

Indicator v5 VolumeSupport & resistance
Updated 2 months ago · MIT GitHub repository of Volume Profile and Indicator by DGT

BZ-tracker

by Allen1212
303 stars

The BZ-tracker indicator marks ARK Invest buy and sell transactions on stock charts with labels. It plots green labels for purchases and red labels for sales, each annotated with a multiplier such as X1 or X2 to show the number of ARK ETFs trading the stock on

Indicator v4 Support & resistanceScreeners & dashboards
Updated 2 years ago · None stated GitHub repository of BZ-tracker

Function - Linear Regression

by ricardosantos79
261 stars

This indicator fits a linear regression through stored pivot highs and lows and draws the resulting channel on the price chart. A function returns predicted values, maximum and minimum deviations, and the average absolute deviation. Confirmed two-bar pivots up

Indicator v5 TrendSupport & resistance
Updated 4 years ago · None stated GitHub repository of Function - Linear Regression

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