IC Markets

Trading zones indicator for scalping

Optimize MetaTrader 4, MetaTrader 5, cTrader, and TradingView for speed. Discuss Level II Market Depth (DOM), custom hotkeys, and volume indicators.
Post Reply
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Trading zones indicator for scalping

Post by PTScalper »

Hi scalpers,

Im sitting at coffee right now and i got an idea for great indicator, i mean zone indicator for start trading/scalping volatility around supports and resistances.

Here is like first version, from which May be i will create automated EA :-)

Here is a professional-grade MQL4 indicator designed specifically for forex scalping. Rather than just plotting single lines, this indicator dynamically calculates and draws Support and Resistance Zones (rectangles) based on recent Swing Highs and Lows.

For scalping, identifying the "liquidity zone" between the wick and the body of a reversal candle is often the most accurate way to define an ideal buying or selling range. This indicator includes that exact price-action logic, alongside an option to use a fixed-pip width.

MQL4 Source Code

1. Open MetaTrader 4 and press F4 to open the MetaEditor.
2. In the Navigator panel, right-click Indicators -> New File -> Custom Indicator.
3. Name it ⁠Scalping_SR_Zones⁠ and click Finish.
4. Replace all the default code with the script below and click Compile.

Code: Select all

 //+------------------------------------------------------------------+
//|                                            Scalping_SR_Zones.mq4 |
//|                                   Professional S&R for Scalping  |
//+------------------------------------------------------------------+
#property copyright "Professional Trading Solutions"
#property version   "1.00"
#property strict
#property indicator_chart_window

enum ENUM_ZONE_CALC {
    ZONE_WICK_BODY = 0,  // Wick to Body (Price Action)
    ZONE_FIXED_PIPS = 1  // Fixed Pips Width
};

//--- Input Parameters
input string         sec1           = "--- Zone Settings ---";
input int            SwingBars      = 12;             // Swing Detection Bars (Left/Right)
input int            MaxZones       = 4;              // Maximum Active Zones per side
input ENUM_ZONE_CALC ZoneCalcMethod = ZONE_WICK_BODY; // Zone Calculation Method
input double         ZonePips       = 3.0;            // Zone Width (if Fixed Pips selected)

input string         sec2           = "--- Visual Settings ---";
input color          ResistanceCol  = clrLightCoral;  // Resistance Zone Color
input color          SupportCol     = clrLightGreen;  // Support Zone Color
input int            ProjectBars    = 15;             // How many bars to project the zone forward

//--- Global Variables
double pipsMult;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Determine pip multiplier for 3/5 digit brokers
   pipsMult = (_Digits == 5 || _Digits == 3) ? _Point * 10 : _Point;
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Clean up chart objects upon removal
   ObjectsDeleteAll(0, "SR_ZONE_");
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   // Ensure we have enough data to calculate swings
   if(rates_total < SwingBars * 2 + 1) return(0);
   
   static datetime lastBarTime = 0;
   datetime currentBarTime = iTime(Symbol(), 0, 0);
   
   // Performance optimization: Only recalculate zones when a new bar opens
   // This prevents chart flickering and reduces CPU load significantly.
   if(lastBarTime == currentBarTime) return(rates_total);
   lastBarTime = currentBarTime;
   
   int resFound = 0;
   int supFound = 0;
   
   // Scan backwards from the most recently closed candles
   for(int i = SwingBars + 1; i < iBars(Symbol(), 0) - SwingBars; i++)
     {
      // Stop scanning if we have found the maximum allowed recent zones
      if(resFound >= MaxZones && supFound >= MaxZones) break;
      
      bool isRes = true;
      bool isSup = true;
      
      double currentHigh = iHigh(Symbol(), 0, i);
      double currentLow  = iLow(Symbol(), 0, i);
      
      // Check surrounding bars to confirm a Swing High or Swing Low
      for(int j = 1; j <= SwingBars; j++)
        {
         if(currentHigh <= iHigh(Symbol(), 0, i+j) || currentHigh <= iHigh(Symbol(), 0, i-j)) isRes = false;
         if(currentLow >= iLow(Symbol(), 0, i+j) || currentLow >= iLow(Symbol(), 0, i-j)) isSup = false;
        }
        
      // If a Resistance Swing High is confirmed
      if(isRes && resFound < MaxZones)
        {
         double topEdge, botEdge;
         if(ZoneCalcMethod == ZONE_FIXED_PIPS) 
           {
            topEdge = currentHigh;
            botEdge = currentHigh - (ZonePips * pipsMult);
           } 
         else 
           {
            topEdge = currentHigh;
            botEdge = MathMax(iOpen(Symbol(), 0, i), iClose(Symbol(), 0, i));
            if(topEdge == botEdge) botEdge = topEdge - (_Point * 10); // Fallback if no wick exists
           }
           
         DrawZone("SR_ZONE_RES_" + IntegerToString(resFound), iTime(Symbol(), 0, i), topEdge, currentBarTime + PeriodSeconds() * ProjectBars, botEdge, ResistanceCol);
         resFound++;
        }
        
      // If a Support Swing Low is confirmed
      if(isSup && supFound < MaxZones)
        {
         double botEdge, topEdge;
         if(ZoneCalcMethod == ZONE_FIXED_PIPS) 
           {
            botEdge = currentLow;
            topEdge = currentLow + (ZonePips * pipsMult);
           } 
         else 
           {
            botEdge = currentLow;
            topEdge = MathMin(iOpen(Symbol(), 0, i), iClose(Symbol(), 0, i));
            if(topEdge == botEdge) topEdge = botEdge + (_Point * 10); // Fallback if no wick exists
           }
           
         DrawZone("SR_ZONE_SUP_" + IntegerToString(supFound), iTime(Symbol(), 0, i), topEdge, currentBarTime + PeriodSeconds() * ProjectBars, botEdge, SupportCol);
         supFound++;
        }
     }

   // Cleanup any residual old zones if the market shifted and fewer zones were found
   for(int k = resFound; k < MaxZones; k++) ObjectDelete(0, "SR_ZONE_RES_" + IntegerToString(k));
   for(int k = supFound; k < MaxZones; k++) ObjectDelete(0, "SR_ZONE_SUP_" + IntegerToString(k));

   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Helper function to draw or update rectangle zones                |
//+------------------------------------------------------------------+
void DrawZone(string name, datetime time1, double price1, datetime time2, double price2, color clr)
  {
   if(ObjectFind(0, name) < 0)
     {
      // Create new object if it doesn't exist
      ObjectCreate(0, name, OBJ_RECTANGLE, 0, time1, price1, time2, price2);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, name, OBJPROP_BACK, true);
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
      ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
      ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
     }
   else
     {
      // Efficiently update existing object coordinates
      ObjectSetInteger(0, name, OBJPROP_TIME, 0, time1);
      ObjectSetDouble(0, name, OBJPROP_PRICE, 0, price1);
      ObjectSetInteger(0, name, OBJPROP_TIME, 1, time2);
      ObjectSetDouble(0, name, OBJPROP_PRICE, 1, price2);
     }
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: Trading zones indicator for scalping

Post by PTScalper »

How to use this for Scalping:

Zone Method (⁠ZONE_WICK_BODY⁠): Institutional order flow often sits inside the wick of a reversal candle. This default setting automatically draws the support zone from the lowest point of the wick up to the candle's closing/opening body. This highlights your precise entry and stop-loss buffer ranges.
Timeframes: For scalping, attach this to the M1, M5, or M15 charts. The algorithm automatically calculates the zones based on the timeframe it is placed on.

Swing Bars: This determines how "major" the zone is. The default of ⁠12⁠ means a candle must be the absolute high/low compared to the 12 candles to its left and right. If you want faster, more aggressive scalping zones on a 1-minute chart, reduce ⁠SwingBars⁠ to ⁠5⁠ or ⁠7⁠.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: Trading zones indicator for scalping

Post by PTScalper »

Here is the exact equivalent logic refactored for MetaTrader 5 (MQL5).
To transition this cleanly to MQL5, a few structural changes were made:

1. Array Sorting: MQL5 passes price arrays (⁠time[]⁠, ⁠high[]⁠, etc.) in standard order by default. The code uses ⁠ArraySetAsSeries()⁠ to index them backwards (0 = current bar) so the historical scanning logic functions exactly like it did in MQL4.

2. Object Filling: In MT5, rectangles often default to just outlines. Added ⁠OBJPROP_FILL⁠ to ensure the zones display as solid background blocks.

3. Chart ID: MQL5 requires explicit Chart IDs for object manipulation, handled via ⁠ChartID()⁠.


MQL5 Source Code

1. Open MetaTrader 5 and press F4 to open the MetaEditor.

2. In the Navigator, right-click Indicators -> New File -> Custom Indicator.

3. Name it ⁠Scalping_SR_Zones_MT5⁠ and click Finish.

4. Replace the default code with this and click Compile.

Code: Select all

 //+------------------------------------------------------------------+
//|                                        Scalping_SR_Zones_MT5.mq5 |
//|                                   Professional S&R for Scalping  |
//+------------------------------------------------------------------+
#property copyright "Professional Trading Solutions"
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0

enum ENUM_ZONE_CALC {
    ZONE_WICK_BODY = 0,  // Wick to Body (Price Action)
    ZONE_FIXED_PIPS = 1  // Fixed Pips Width
};

//--- Input Parameters
input string         sec1           = "--- Zone Settings ---";
input int            SwingBars      = 12;             // Swing Detection Bars (Left/Right)
input int            MaxZones       = 4;              // Maximum Active Zones per side
input ENUM_ZONE_CALC ZoneCalcMethod = ZONE_WICK_BODY; // Zone Calculation Method
input double         ZonePips       = 3.0;            // Zone Width (if Fixed Pips selected)

input string         sec2           = "--- Visual Settings ---";
input color          ResistanceCol  = clrLightCoral;  // Resistance Zone Color
input color          SupportCol     = clrLightGreen;  // Support Zone Color
input int            ProjectBars    = 15;             // How many bars to project the zone forward

//--- Global Variables
double pipsMult;
long   chart_id;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   chart_id = ChartID();
   // Determine pip multiplier for 3/5 digit brokers
   pipsMult = (_Digits == 5 || _Digits == 3) ? _Point * 10 : _Point;
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Clean up chart objects upon removal
   ObjectsDeleteAll(chart_id, "SR_ZONE_");
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   // Ensure we have enough data to calculate swings
   if(rates_total < SwingBars * 2 + 1) return(0);
   
   // MQL5 specific: Reorder arrays to match MQL4 indexing (0 = current bar)
   ArraySetAsSeries(time, true);
   ArraySetAsSeries(open, true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(close, true);
   
   static datetime lastBarTime = 0;
   datetime currentBarTime = time[0];
   
   // Performance optimization: Only recalculate when a new bar opens
   if(lastBarTime == currentBarTime) return(rates_total);
   lastBarTime = currentBarTime;
   
   int resFound = 0;
   int supFound = 0;
   
   // Scan backwards from the most recently closed candles
   for(int i = SwingBars + 1; i < rates_total - SwingBars; i++)
     {
      // Stop scanning if we have found the maximum allowed recent zones
      if(resFound >= MaxZones && supFound >= MaxZones) break;
      
      bool isRes = true;
      bool isSup = true;
      
      double currentHigh = high[i];
      double currentLow  = low[i];
      
      // Check surrounding bars to confirm a Swing High or Swing Low
      for(int j = 1; j <= SwingBars; j++)
        {
         if(currentHigh <= high[i+j] || currentHigh <= high[i-j]) isRes = false;
         if(currentLow >= low[i+j] || currentLow >= low[i-j]) isSup = false;
        }
        
      // If a Resistance Swing High is confirmed
      if(isRes && resFound < MaxZones)
        {
         double topEdge, botEdge;
         if(ZoneCalcMethod == ZONE_FIXED_PIPS) 
           {
            topEdge = currentHigh;
            botEdge = currentHigh - (ZonePips * pipsMult);
           } 
         else 
           {
            topEdge = currentHigh;
            botEdge = MathMax(open[i], close[i]);
            if(topEdge == botEdge) botEdge = topEdge - (_Point * 10); // Fallback if no wick
           }
           
         DrawZone("SR_ZONE_RES_" + IntegerToString(resFound), time[i], topEdge, currentBarTime + PeriodSeconds() * ProjectBars, botEdge, ResistanceCol);
         resFound++;
        }
        
      // If a Support Swing Low is confirmed
      if(isSup && supFound < MaxZones)
        {
         double botEdge, topEdge;
         if(ZoneCalcMethod == ZONE_FIXED_PIPS) 
           {
            botEdge = currentLow;
            topEdge = currentLow + (ZonePips * pipsMult);
           } 
         else 
           {
            botEdge = currentLow;
            topEdge = MathMin(open[i], close[i]);
            if(topEdge == botEdge) topEdge = botEdge + (_Point * 10); // Fallback if no wick
           }
           
         DrawZone("SR_ZONE_SUP_" + IntegerToString(supFound), time[i], topEdge, currentBarTime + PeriodSeconds() * ProjectBars, botEdge, SupportCol);
         supFound++;
        }
     }

   // Cleanup any residual old zones if the market shifted
   for(int k = resFound; k < MaxZones; k++) ObjectDelete(chart_id, "SR_ZONE_RES_" + IntegerToString(k));
   for(int k = supFound; k < MaxZones; k++) ObjectDelete(chart_id, "SR_ZONE_SUP_" + IntegerToString(k));

   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Helper function to draw or update rectangle zones                |
//+------------------------------------------------------------------+
void DrawZone(string name, datetime time1, double price1, datetime time2, double price2, color clr)
  {
   if(ObjectFind(chart_id, name) < 0)
     {
      // Create new object
      ObjectCreate(chart_id, name, OBJ_RECTANGLE, 0, time1, price1, time2, price2);
      ObjectSetInteger(chart_id, name, OBJPROP_COLOR, clr);
      ObjectSetInteger(chart_id, name, OBJPROP_BACK, true);
      ObjectSetInteger(chart_id, name, OBJPROP_STYLE, STYLE_SOLID);
      ObjectSetInteger(chart_id, name, OBJPROP_HIDDEN, true);
      ObjectSetInteger(chart_id, name, OBJPROP_SELECTABLE, false);
      
      // MT5 specific requirement for solid rectangle backgrounds
      ObjectSetInteger(chart_id, name, OBJPROP_FILL, true);
     }
   else
     {
      // Efficiently update existing object coordinates
      ObjectSetInteger(chart_id, name, OBJPROP_TIME, 0, time1);
      ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 0, price1);
      ObjectSetInteger(chart_id, name, OBJPROP_TIME, 1, time2);
      ObjectSetDouble(chart_id, name, OBJPROP_PRICE, 1, price2);
     }
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: Trading zones indicator for scalping

Post by PTScalper »

Here is the cTrader (cAlgo) equivalent written in C#.
The transition to cTrader’s API allows for a slightly cleaner object-oriented structure. I’ve included an alpha channel adjustment during the ⁠Initialize()⁠ method—this adds transparency to the zones so they don't block out the candles when ⁠IsFilled⁠ is set to true, which is a common quirk with cTrader's ⁠ChartRectangle⁠ objects.

cTrader Automate Source Code

1. Open cTrader and switch to the Automate tab on the left.

2. Under Indicators, click New and name it ⁠ScalpingSRZones⁠.

3. Paste the C# script below and click Build (or press Ctrl+B).

Code: Select all

 using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ScalpingSRZones : Indicator
    {
        public enum CalcMethod
        {
            WickToBody,
            FixedPips
        }

        [Parameter("Swing Bars", Group = "Zone Settings", DefaultValue = 12, MinValue = 2)]
        public int SwingBars { get; set; }

        [Parameter("Max Zones", Group = "Zone Settings", DefaultValue = 4, MinValue = 1)]
        public int MaxZones { get; set; }

        [Parameter("Zone Calculation", Group = "Zone Settings", DefaultValue = CalcMethod.WickToBody)]
        public CalcMethod ZoneCalculationMethod { get; set; }

        [Parameter("Fixed Pips Width", Group = "Zone Settings", DefaultValue = 3.0, MinValue = 0.1)]
        public double ZonePips { get; set; }

        [Parameter("Resistance Color (Name)", Group = "Visuals", DefaultValue = "LightCoral")]
        public string ResColorName { get; set; }

        [Parameter("Support Color (Name)", Group = "Visuals", DefaultValue = "LightGreen")]
        public string SupColorName { get; set; }

        [Parameter("Project Bars", Group = "Visuals", DefaultValue = 15, MinValue = 1)]
        public int ProjectBars { get; set; }

        private Color _resistanceColor;
        private Color _supportColor;
        private int _lastIndex = -1;

        protected override void Initialize()
        {
            // Parse base colors from the parameter strings
            Color baseResColor = Color.FromName(ResColorName);
            Color baseSupColor = Color.FromName(SupColorName);
            
            // Add a 100-level alpha channel for transparency to prevent obscuring price action
            _resistanceColor = Color.FromArgb(100, baseResColor);
            _supportColor = Color.FromArgb(100, baseSupColor);
        }

        public override void Calculate(int index)
        {
            // Ensure enough data is present
            if (index < SwingBars * 2) return;
            
            // Performance optimization: Execute only on the tick of a new bar opening
            if (index == _lastIndex) return;
            _lastIndex = index;

            int resFound = 0;
            int supFound = 0;

            // Calculate exact projection time robustly across any timeframe
            TimeSpan barPeriod = Bars.OpenTimes[index] - Bars.OpenTimes[index - 1];
            DateTime projectedTime = Bars.OpenTimes[index].Add(TimeSpan.FromTicks(barPeriod.Ticks * ProjectBars));

            // Scan backwards from the closed candles
            for (int i = index - SwingBars - 1; i >= SwingBars; i--)
            {
                if (resFound >= MaxZones && supFound >= MaxZones) break;

                bool isRes = true;
                bool isSup = true;

                double currentHigh = Bars.HighPrices[i];
                double currentLow = Bars.LowPrices[i];

                // Validate Swing Highs/Lows against surrounding bars
                for (int j = 1; j <= SwingBars; j++)
                {
                    if (currentHigh <= Bars.HighPrices[i + j] || currentHigh <= Bars.HighPrices[i - j]) isRes = false;
                    if (currentLow >= Bars.LowPrices[i + j] || currentLow >= Bars.LowPrices[i - j]) isSup = false;
                }

                if (isRes && resFound < MaxZones)
                {
                    double topEdge = currentHigh;
                    double botEdge = ZoneCalculationMethod == CalcMethod.FixedPips 
                        ? currentHigh - (ZonePips * Symbol.PipSize)
                        : Math.Max(Bars.OpenPrices[i], Bars.ClosePrices[i]);

                    // Fallback width if no wick exists
                    if (topEdge == botEdge) botEdge -= Symbol.PipSize; 

                    var rect = Chart.DrawRectangle("SR_RES_" + resFound, Bars.OpenTimes[i], topEdge, projectedTime, botEdge, _resistanceColor);
                    rect.IsFilled = true;
                    resFound++;
                }

                if (isSup && supFound < MaxZones)
                {
                    double botEdge = currentLow;
                    double topEdge = ZoneCalculationMethod == CalcMethod.FixedPips
                        ? currentLow + (ZonePips * Symbol.PipSize)
                        : Math.Min(Bars.OpenPrices[i], Bars.ClosePrices[i]);

                    // Fallback width if no wick exists
                    if (topEdge == botEdge) topEdge += Symbol.PipSize; 

                    var rect = Chart.DrawRectangle("SR_SUP_" + supFound, Bars.OpenTimes[i], topEdge, projectedTime, botEdge, _supportColor);
                    rect.IsFilled = true;
                    supFound++;
                }
            }

            // Cleanup obsolete chart objects if market structures shift
            for (int k = resFound; k < MaxZones; k++) Chart.RemoveObject("SR_RES_" + k);
            for (int k = supFound; k < MaxZones; k++) Chart.RemoveObject("SR_SUP_" + k);
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: Trading zones indicator for scalping

Post by PTScalper »

Here is the TradingView (Pine Script v5) equivalent.
Because Pine Script processes data chronologically from left to right (unlike MQL and C# which can easily run backward loops over arrays), this version uses TradingView's built-in ⁠ta.pivothigh()⁠ / ⁠ta.pivotlow()⁠ functions to detect the structures, and ⁠box⁠ arrays to manage the active zones.
It replicates the exact behavior of the previous scripts: it finds the most recent ⁠MaxZones⁠, draws from wick to body (or fixed pips), and dynamically drags the right edge of the boxes forward into the future as new candles print.

Pine Script v5 Source Code

1. Open TradingView and click the Pine Editor tab at the bottom.

2. Delete any existing code and paste the script below.

3. Click Add to Chart.

Code: Select all

 //@version=5
indicator("Scalping S&R Zones", overlay=true, max_boxes_count=100)

// --- Input Parameters ---
grp1 = "--- Zone Settings ---"
swingBars  = input.int(12, title="Swing Detection Bars", group=grp1, tooltip="Bars left and right required to confirm a swing")
maxZones   = input.int(4, title="Maximum Active Zones", group=grp1)
calcMethod = input.string("Wick to Body", options=["Wick to Body", "Fixed Pips"], title="Zone Calculation", group=grp1)
zonePips   = input.float(3.0, title="Zone Width (Pips)", group=grp1)

grp2 = "--- Visual Settings ---"
// In Pine, transparency is 0 (solid) to 100 (invisible). 70 gives a nice background highlight.
resColor    = input.color(color.new(color.maroon, 70), title="Resistance Color", group=grp2)
supColor    = input.color(color.new(color.green, 70), title="Support Color", group=grp2)
projectBars = input.int(15, title="Project Forward Bars", group=grp2)

// --- Global Variables & Arrays ---
// Auto-adjust pip size depending on whether the symbol is forex or another asset
pipSize = syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)

// Arrays to store the active box IDs
var box[] resBoxes = array.new_box()
var box[] supBoxes = array.new_box()

// --- Swing Detection ---
// ta.pivothigh/low looks back 'swingBars' left and right to confirm a peak/trough
pivotHigh = ta.pivothigh(high, swingBars, swingBars)
pivotLow  = ta.pivotlow(low, swingBars, swingBars)

// The actual index of the pivot candle is 'swingBars' bars ago from the current candle
pivotIndex = bar_index[swingBars]

// --- Resistance Zones ---
if not na(pivotHigh)
    float topEdge = high[swingBars]
    float botEdge = calcMethod == "Fixed Pips" ? topEdge - (zonePips * pipSize) : math.max(open[swingBars], close[swingBars])
    
    if topEdge == botEdge
        botEdge -= pipSize // Fallback if no wick exists
        
    // Create the rectangular zone
    b = box.new(left=pivotIndex, top=topEdge, right=bar_index + projectBars, bottom=botEdge, 
         border_color=color.new(resColor, 100), bgcolor=resColor)
         
    array.push(resBoxes, b)
    
    // Remove the oldest zone if we exceed the MaxZones limit
    if array.size(resBoxes) > maxZones
        box.delete(array.shift(resBoxes))

// --- Support Zones ---
if not na(pivotLow)
    float botEdge = low[swingBars]
    float topEdge = calcMethod == "Fixed Pips" ? botEdge + (zonePips * pipSize) : math.min(open[swingBars], close[swingBars])
    
    if topEdge == botEdge
        topEdge += pipSize // Fallback if no wick exists
        
    // Create the rectangular zone
    b = box.new(left=pivotIndex, top=topEdge, right=bar_index + projectBars, bottom=botEdge, 
         border_color=color.new(supColor, 100), bgcolor=supColor)
         
    array.push(supBoxes, b)
    
    // Remove the oldest zone if we exceed the MaxZones limit
    if array.size(supBoxes) > maxZones
        box.delete(array.shift(supBoxes))

// --- Dynamic Forward Projection ---
// Continuously stretch the active zones to the right as new real-time bars print
if array.size(resBoxes) > 0
    for i = 0 to array.size(resBoxes) - 1
        box.set_right(array.get(resBoxes, i), bar_index + projectBars)

if array.size(supBoxes) > 0
    for i = 0 to array.size(supBoxes) - 1
        box.set_right(array.get(supBoxes, i), bar_index + projectBars)
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: Trading zones indicator for scalping

Post by PTScalper »

Please let me know, if it was helpfull for you :-)

Take a care.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply