Page 1 of 1

1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:08 pm
by PTScalper
Hi guys,
here is my naked Chart 1-Minute Forex Scalping Strategy (No Indicators!)

I’ve seen a lot of posts lately about cluttered charts—people relying on MACD, RSI, and overlapping moving averages just to scalp the 1-minute time frame. Honestly, I found that all that noise just causes analysis paralysis. So, I stripped my charts completely bare. Today, I want to share my pure price action, 1-minute scalping strategy that relies purely on market structure and liquidity pools.

1.Mark the Zones:First, analyze the 15-minute chart to establish your daily bias and map out major support and resistance levels.
2.Wait for the Sweep:Drop to the 1-minute chart. Wait patiently for the price to sweep a recent swing low (for a buy) or a swing high (for a sell).
3.Identify a Break of Structure:After the sweep, look for an impulsive reversal. For a buy, price must break above the most recent lower high, confirming the sweep was just a liquidity grab.
4.Time The Entry:Don't chase the initial move! Wait for a pullback into the "golden zone." Enter when the price retraces to the 0.5 to 0.618 Fibonacci level of that impulsive leg, or target the M1 order block left behind.5.Set Risk Management:Place a tight stop loss 1 to 2 pips beyond the sweep candle’s wick. Target the next obvious liquidity pool for a 1:2 risk-to-reward ratio.Why It WorksBy trading naked charts, you react to actual market mechanics rather than lagging math equations.
It requires intense discipline, but once you train your eyes to read these sweeps, the 1-minute chart becomes incredibly clear.Who else is scalping naked charts?
Drop your thoughts below!

Take a care,
have a great trades,
bye bye.

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:09 pm
by PTScalper
Plus i tried to prepare usefull script to detect such zones for you ;-)

Here is a custom MQL4 indicator designed specifically for the 1-minute scalping strategy. It uses dynamic lookback arrays to identify the most recent market structure extremes and renders "buy-side" and "sell-side" liquidity zones.

MQL4 Source Code: Liquidity Sweep Zones
Save this script as an .mq4 file. It relies on standard C++ style syntax with #property strict enabled for memory safety and clean execution.

Code: Select all

//+------------------------------------------------------------------+
//|                                      Liquidity_Sweep_Zones.mq4   |
//|                    Detects dynamic buy/sell liquidity pools      |
//+------------------------------------------------------------------+
#property copyright "Automated Zone Detector"
#property version   "1.00"
#property strict
#property indicator_chart_window

input int    InpLookbackBars = 40;         // Lookback Period (Bars)
input int    InpZoneWidthPips = 2;         // Zone Depth (Pips)
input color  InpSweepHighColor = clrLightCoral; // Sell Side Liquidity (Sweep High)
input color  InpSweepLowColor = clrLightGreen;  // Buy Side Liquidity (Sweep Low)

//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   // Clean up graphical objects when the indicator is removed
   ObjectsDeleteAll(0, "LiqPool_");
  }

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 enough data is loaded
   if (rates_total < InpLookbackBars) return(0);

   // Isolate recent market structure extremes
   int highest_idx = ArrayMaximum(high, InpLookbackBars, 1);
   int lowest_idx  = ArrayMinimum(low, InpLookbackBars, 1);
   
   double swing_high = high[highest_idx];
   double swing_low  = low[lowest_idx];
   
   // Handle 3/5 digit broker pricing
   double pip_multiplier = (Digits() == 3 || Digits() == 5) ? 10.0 : 1.0;
   double zone_height = InpZoneWidthPips * Point() * pip_multiplier;

   // Render structural liquidity rectangles extending slightly into the future
   DrawZone("LiqPool_High", time[highest_idx], swing_high, Time[0] + PeriodSeconds()*10, swing_high - zone_height, InpSweepHighColor);
   DrawZone("LiqPool_Low", time[lowest_idx], swing_low, Time[0] + PeriodSeconds()*10, swing_low + zone_height, InpSweepLowColor);

   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Helper function to manage OBJ_RECTANGLE states                   |
//+------------------------------------------------------------------+
void DrawZone(string obj_name, datetime t1, double p1, datetime t2, double p2, color clr)
  {
   if(ObjectFind(0, obj_name) < 0)
     {
      ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, t1, p1, t2, p2);
      ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
      ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
      ObjectSetInteger(0, obj_name, OBJPROP_HIDDEN, true);
     }
   else
     {
      // Update coordinates dynamically on new ticks
      ObjectSetInteger(0, obj_name, OBJPROP_TIME1, t1);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE1, p1);
      ObjectSetInteger(0, obj_name, OBJPROP_TIME2, t2);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE2, p2);
     }
  }
//+------------------------------------------------------------------+

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:10 pm
by PTScalper
Logic BreakdownDynamic Arrays:

The script uses ArrayMaximum and ArrayMinimum to scan the defined lookback period and grab the precise index of the swing points.Object Management: Instead of flooding the chart with overlapping boxes, the DrawZone helper function creates two persistent OBJ_RECTANGLE entities and simply recalculates their coordinates on every tick. This is computationally inexpensive and keeps the chart clean.Broker Independence: The pip_multiplier logic automatically adjusts for standard 4-digit and fractional 5-digit pricing models.

1.Open MetaEditor:Press F4 in your MT4 terminal to open the IDE.

2.Create a New Custom Indicator:Select "New" -> "Custom Indicator", name it Liquidity_Sweep_Zones, and click Finish.

3.Compile the Code:Overwrite the generated template with the provided MQL4 code and press F7 to compile.4.Apply to Chart:Return to MT4, locate the newly compiled script in your Navigator panel, and drag it onto your 1-minute chart.

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:11 pm
by PTScalper
And i prepared second version, where i have implemented alert notifications:

Code: Select all

//+------------------------------------------------------------------+
//|                                      Liquidity_Sweep_Zones.mq4   |
//|                    Detects dynamic buy/sell liquidity pools      |
//+------------------------------------------------------------------+
#property copyright "Automated Zone Detector"
#property version   "1.10"
#property strict
#property indicator_chart_window

// Zone Inputs
input int    InpLookbackBars = 40;         // Lookback Period (Bars)
input int    InpZoneWidthPips = 2;         // Zone Depth (Pips)
input color  InpSweepHighColor = clrLightCoral; // Sell Side Liquidity (Sweep High)
input color  InpSweepLowColor = clrLightGreen;  // Buy Side Liquidity (Sweep Low)

// Alert Inputs
input bool   InpEnableAlerts = true;       // Master Alert Toggle
input bool   InpEnablePush = true;         // Send Push Notifications
input bool   InpEnableSound = true;        // Play Sound
input string InpSoundFile = "alert.wav";   // Alert Sound File (WAV format)

//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, "LiqPool_");
  }

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[])
  {
   if (rates_total < InpLookbackBars) return(0);

   // Isolate recent market structure extremes
   int highest_idx = ArrayMaximum(high, InpLookbackBars, 1);
   int lowest_idx  = ArrayMinimum(low, InpLookbackBars, 1);
   
   double swing_high = high[highest_idx];
   double swing_low  = low[lowest_idx];
   
   double pip_multiplier = (Digits() == 3 || Digits() == 5) ? 10.0 : 1.0;
   double zone_height = InpZoneWidthPips * Point() * pip_multiplier;

   double sell_zone_bottom = swing_high - zone_height;
   double buy_zone_top = swing_low + zone_height;

   // Render structural liquidity rectangles
   DrawZone("LiqPool_High", time[highest_idx], swing_high, Time[0] + PeriodSeconds()*10, sell_zone_bottom, InpSweepHighColor);
   DrawZone("LiqPool_Low", time[lowest_idx], swing_low, Time[0] + PeriodSeconds()*10, buy_zone_top, InpSweepLowColor);

   // --- ALERT LOGIC ---
   // Use a static datetime to persist the state between ticks
   static datetime last_alert_time = 0;
   
   // Only evaluate if alerts are on and we haven't alerted on this specific M1 candle yet
   if(InpEnableAlerts && Time[0] != last_alert_time)
     {
      bool alert_triggered = false;
      string alert_msg = "";

      // Check if current Close is inside the Sell Side Liquidity Zone
      if(Close[0] >= sell_zone_bottom && Close[0] <= swing_high)
        {
         alert_msg = Symbol() + " M" + IntegerToString(Period()) + ": Price entered SELL Liquidity Zone";
         alert_triggered = true;
        }
      // Check if current Close is inside the Buy Side Liquidity Zone
      else if(Close[0] <= buy_zone_top && Close[0] >= swing_low)
        {
         alert_msg = Symbol() + " M" + IntegerToString(Period()) + ": Price entered BUY Liquidity Zone";
         alert_triggered = true;
        }

      // Dispatch notifications
      if(alert_triggered)
        {
         if(InpEnablePush) 
           {
            SendNotification(alert_msg);
           }
         if(InpEnableSound) 
           {
            PlaySound(InpSoundFile);
           }
         
         // Log to the Experts tab for debugging
         Print(alert_msg); 
         
         // Lock the state for the remainder of this candle
         last_alert_time = Time[0]; 
        }
     }

   return(rates_total);
  }

//+------------------------------------------------------------------+
void DrawZone(string obj_name, datetime t1, double p1, datetime t2, double p2, color clr)
  {
   if(ObjectFind(0, obj_name) < 0)
     {
      ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, t1, p1, t2, p2);
      ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
      ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
      ObjectSetInteger(0, obj_name, OBJPROP_HIDDEN, true);
     }
   else
     {
      ObjectSetInteger(0, obj_name, OBJPROP_TIME1, t1);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE1, p1);
      ObjectSetInteger(0, obj_name, OBJPROP_TIME2, t2);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE2, p2);
     }
  }
//+------------------------------------------------------------------+

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:13 pm
by PTScalper
And in case, you would like to try it as fully automated AI, you can try this script, it should work for you.
But do not forget to test it first :-)

Here is the complete EA code. It integrates the previous zone-detection logic, adds a state-tracking mechanism using a Magic Number, and handles the OrderSend routing with integrated Stop Loss and Take Profit parameters.

MQL4 Source Code: Liquidity Sweep Auto-Scalper

Code: Select all

//+------------------------------------------------------------------+
//|                                   Liquidity_Sweep_Scalper_EA.mq4 |
//|                 Automated Execution for Liquidity Pool Sweeps    |
//+------------------------------------------------------------------+
#property copyright "Automated Zone Scalper EA"
#property version   "1.00"
#property strict

// --- Trading Parameters ---
input double InpLotSize = 0.10;            // Fixed Lot Size
input int    InpStopLossPips = 5;          // Stop Loss (Pips)
input int    InpTakeProfitPips = 10;       // Take Profit (Pips)
input int    InpMaxSlippage = 3;           // Max Slippage (Pips)
input int    InpMagicNumber = 999111;      // EA Identifier

// --- Zone Parameters ---
input int    InpLookbackBars = 40;         // Lookback Period (Bars)
input int    InpZoneWidthPips = 2;         // Zone Depth (Pips)
input color  InpSweepHighColor = clrLightCoral;
input color  InpSweepLowColor = clrLightGreen;

//+------------------------------------------------------------------+
int OnInit()
  {
   // Validate inputs
   if(InpStopLossPips <= 0 || InpTakeProfitPips <= 0)
     {
      Print("Invalid SL/TP configuration.");
      return(INIT_PARAMETERS_INCORRECT);
     }
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, "LiqPool_");
  }

void OnTick()
  {
   // Ensure enough historical data is available
   if (Bars < InpLookbackBars) return;

   // 1. Calculate Pricing Variables
   double pip_size = (Digits() == 3 || Digits() == 5) ? 10.0 * Point() : Point();
   int slippage_points = (Digits() == 3 || Digits() == 5) ? InpMaxSlippage * 10 : InpMaxSlippage;

   // 2. Identify Market Structure Extremes
   int highest_idx = iHighest(Symbol(), Period(), MODE_HIGH, InpLookbackBars, 1);
   int lowest_idx  = iLowest(Symbol(), Period(), MODE_LOW, InpLookbackBars, 1);
   
   double swing_high = High[highest_idx];
   double swing_low  = Low[lowest_idx];
   
   double zone_height = InpZoneWidthPips * pip_size;
   double sell_zone_bottom = swing_high - zone_height;
   double buy_zone_top = swing_low + zone_height;

   // 3. Render GUI (Optional for EAs, but helpful for visual debugging)
   DrawZone("LiqPool_High", Time[highest_idx], swing_high, Time[0] + PeriodSeconds()*10, sell_zone_bottom, InpSweepHighColor);
   DrawZone("LiqPool_Low", Time[lowest_idx], swing_low, Time[0] + PeriodSeconds()*10, buy_zone_top, InpSweepLowColor);

   // 4. State Management: Check for open positions managed by this EA
   if(HasOpenPositions(InpMagicNumber)) return; // Lock execution if a trade is active

   // 5. Execution Logic
   double ask = MarketInfo(Symbol(), MODE_ASK);
   double bid = MarketInfo(Symbol(), MODE_BID);

   // SELL Condition: Price enters the upper liquidity zone
   if(Close[0] >= sell_zone_bottom && Close[0] <= swing_high)
     {
      double sl = NormalizeDouble(bid + (InpStopLossPips * pip_size), Digits());
      double tp = NormalizeDouble(bid - (InpTakeProfitPips * pip_size), Digits());
      
      int ticket = OrderSend(Symbol(), OP_SELL, InpLotSize, bid, slippage_points, sl, tp, "Liq Sweep Sell", InpMagicNumber, 0, clrRed);
      
      if(ticket < 0) Print("OrderSend Error: ", GetLastError());
     }
     
   // BUY Condition: Price enters the lower liquidity zone
   else if(Close[0] <= buy_zone_top && Close[0] >= swing_low)
     {
      double sl = NormalizeDouble(ask - (InpStopLossPips * pip_size), Digits());
      double tp = NormalizeDouble(ask + (InpTakeProfitPips * pip_size), Digits());
      
      int ticket = OrderSend(Symbol(), OP_BUY, InpLotSize, ask, slippage_points, sl, tp, "Liq Sweep Buy", InpMagicNumber, 0, clrBlue);
      
      if(ticket < 0) Print("OrderSend Error: ", GetLastError());
     }
  }

//+------------------------------------------------------------------+
//| Helper: Check if EA has open positions                           |
//+------------------------------------------------------------------+
bool HasOpenPositions(int magic_num)
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic_num)
           {
            return true;
           }
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Helper: Manage GUI objects                                       |
//+------------------------------------------------------------------+
void DrawZone(string obj_name, datetime t1, double p1, datetime t2, double p2, color clr)
  {
   if(ObjectFind(0, obj_name) < 0)
     {
      ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, t1, p1, t2, p2);
      ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
      ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
      ObjectSetInteger(0, obj_name, OBJPROP_HIDDEN, true);
     }
   else
     {
      ObjectSetInteger(0, obj_name, OBJPROP_TIME1, t1);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE1, p1);
      ObjectSetInteger(0, obj_name, OBJPROP_TIME2, t2);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE2, p2);
     }
  }
//+------------------------------------------------------------------+

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:14 pm
by PTScalper
Architecture Breakdown

1.) OnTick() Hook: This replaces OnCalculate(). It fires every time the broker pushes a new price quote.

2.) The Magic Number: A unique integer (999111) is assigned to every trade this specific EA executes. The HasOpenPositions function iterates through the terminal's active order pool and checks this ID. If an order exists, the EA bypasses the entry logic, preventing rapid-fire duplicate orders in the same zone.

3.) Data Retrieval Shift: Instead of using the pre-populated arrays from OnCalculate (like high[] and low[]), the EA pulls structural data directly from the terminal using iHighest and iLowest.

4.) Price Normalization: The NormalizeDouble function is critical here. 1-minute charts have highly volatile fractional pricing. Sending un-normalized doubles to the broker's API will result in Error 130 (ERR_INVALID_STOPS).

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:15 pm
by PTScalper
Plus i got idea how to make it more robust, i extend it with trailing stop mechanism.

To implement a dynamic trailing stop, the EA needs to shift from a "fire and forget" model to continuous trade management.

When you introduce a trailing stop, the EA must evaluate the profit of open positions on every single tick. To prevent the EA from spamming your broker's server with modification requests for every micro-pip movement, we will introduce a Trailing Step. This ensures the Stop Loss only moves when the price has advanced by a meaningful, predefined increment.

Here is the fully updated EA with the integrated trailing stop logic.

Updated MQL4 Source Code: EA with Trailing Stop

Code: Select all

//+------------------------------------------------------------------+
//|                                   Liquidity_Sweep_Scalper_EA.mq4 |
//|                 Automated Execution with Dynamic Trailing Stop   |
//+------------------------------------------------------------------+
#property copyright "Automated Zone Scalper EA"
#property version   "1.10"
#property strict

// --- Trading Parameters ---
input double InpLotSize = 0.10;            // Fixed Lot Size
input int    InpStopLossPips = 5;          // Initial Stop Loss (Pips)
input int    InpTakeProfitPips = 10;       // Take Profit (Pips)
input int    InpMaxSlippage = 3;           // Max Slippage (Pips)
input int    InpMagicNumber = 999111;      // EA Identifier

// --- Trailing Stop Parameters ---
input bool   InpUseTrailingStop = true;    // Enable Trailing Stop
input int    InpTrailingStopPips = 4;      // Distance behind price (Pips)
input int    InpTrailingStepPips = 1;      // Minimum move before adjusting (Pips)

// --- Zone Parameters ---
input int    InpLookbackBars = 40;         // Lookback Period (Bars)
input int    InpZoneWidthPips = 2;         // Zone Depth (Pips)
input color  InpSweepHighColor = clrLightCoral;
input color  InpSweepLowColor = clrLightGreen;

//+------------------------------------------------------------------+
int OnInit()
  {
   if(InpStopLossPips <= 0 || InpTakeProfitPips <= 0)
     {
      Print("Invalid SL/TP configuration.");
      return(INIT_PARAMETERS_INCORRECT);
     }
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, "LiqPool_");
  }

void OnTick()
  {
   if (Bars < InpLookbackBars) return;

   // 1. Calculate Pricing Variables
   double pip_size = (Digits() == 3 || Digits() == 5) ? 10.0 * Point() : Point();
   int slippage_points = (Digits() == 3 || Digits() == 5) ? InpMaxSlippage * 10 : InpMaxSlippage;

   // 2. Manage Open Positions (Trailing Stop)
   // This MUST happen before the HasOpenPositions check so it runs on every tick
   if(InpUseTrailingStop)
     {
      ManageTrailingStops(pip_size);
     }

   // 3. State Management: Prevent multiple entries
   if(HasOpenPositions(InpMagicNumber)) return; 

   // 4. Identify Market Structure Extremes
   int highest_idx = iHighest(Symbol(), Period(), MODE_HIGH, InpLookbackBars, 1);
   int lowest_idx  = iLowest(Symbol(), Period(), MODE_LOW, InpLookbackBars, 1);
   
   double swing_high = High[highest_idx];
   double swing_low  = Low[lowest_idx];
   
   double zone_height = InpZoneWidthPips * pip_size;
   double sell_zone_bottom = swing_high - zone_height;
   double buy_zone_top = swing_low + zone_height;

   // 5. Render GUI
   DrawZone("LiqPool_High", Time[highest_idx], swing_high, Time[0] + PeriodSeconds()*10, sell_zone_bottom, InpSweepHighColor);
   DrawZone("LiqPool_Low", Time[lowest_idx], swing_low, Time[0] + PeriodSeconds()*10, buy_zone_top, InpSweepLowColor);

   // 6. Execution Logic
   double ask = MarketInfo(Symbol(), MODE_ASK);
   double bid = MarketInfo(Symbol(), MODE_BID);

   // SELL Condition
   if(Close[0] >= sell_zone_bottom && Close[0] <= swing_high)
     {
      double sl = NormalizeDouble(bid + (InpStopLossPips * pip_size), Digits());
      double tp = NormalizeDouble(bid - (InpTakeProfitPips * pip_size), Digits());
      
      int ticket = OrderSend(Symbol(), OP_SELL, InpLotSize, bid, slippage_points, sl, tp, "Liq Sweep Sell", InpMagicNumber, 0, clrRed);
      if(ticket < 0) Print("OrderSend Error: ", GetLastError());
     }
     
   // BUY Condition
   else if(Close[0] <= buy_zone_top && Close[0] >= swing_low)
     {
      double sl = NormalizeDouble(ask - (InpStopLossPips * pip_size), Digits());
      double tp = NormalizeDouble(ask + (InpTakeProfitPips * pip_size), Digits());
      
      int ticket = OrderSend(Symbol(), OP_BUY, InpLotSize, ask, slippage_points, sl, tp, "Liq Sweep Buy", InpMagicNumber, 0, clrBlue);
      if(ticket < 0) Print("OrderSend Error: ", GetLastError());
     }
  }

//+------------------------------------------------------------------+
//| Subroutine: Manage Dynamic Trailing Stops                        |
//+------------------------------------------------------------------+
void ManageTrailingStops(double pip_size)
  {
   double trailing_dist = InpTrailingStopPips * pip_size;
   double trailing_step = InpTrailingStepPips * pip_size;
   
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
           {
            // Manage BUY Order
            if(OrderType() == OP_BUY)
              {
               double new_sl = NormalizeDouble(Bid - trailing_dist, Digits());
               
               // Check if price is in profit enough to start trailing
               if(Bid - OrderOpenPrice() > trailing_dist)
                 {
                  // Only modify if the new SL is higher than the old one by the trailing step
                  if(OrderStopLoss() < new_sl - trailing_step || OrderStopLoss() == 0)
                    {
                     bool res = OrderModify(OrderTicket(), OrderOpenPrice(), new_sl, OrderTakeProfit(), 0, clrGreen);
                     if(!res) Print("Error modifying Buy SL: ", GetLastError());
                    }
                 }
              }
              
            // Manage SELL Order
            else if(OrderType() == OP_SELL)
              {
               double new_sl = NormalizeDouble(Ask + trailing_dist, Digits());
               
               // Check if price is in profit enough to start trailing
               if(OrderOpenPrice() - Ask > trailing_dist)
                 {
                  // Only modify if the new SL is lower than the old one by the trailing step
                  if(OrderStopLoss() > new_sl + trailing_step || OrderStopLoss() == 0)
                    {
                     bool res = OrderModify(OrderTicket(), OrderOpenPrice(), new_sl, OrderTakeProfit(), 0, clrRed);
                     if(!res) Print("Error modifying Sell SL: ", GetLastError());
                    }
                 }
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
bool HasOpenPositions(int magic_num)
  {
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic_num) return true;
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
void DrawZone(string obj_name, datetime t1, double p1, datetime t2, double p2, color clr)
  {
   if(ObjectFind(0, obj_name) < 0)
     {
      ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, t1, p1, t2, p2);
      ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
      ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
      ObjectSetInteger(0, obj_name, OBJPROP_HIDDEN, true);
     }
   else
     {
      ObjectSetInteger(0, obj_name, OBJPROP_TIME1, t1);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE1, p1);
      ObjectSetInteger(0, obj_name, OBJPROP_TIME2, t2);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE2, p2);
     }
  }
//+------------------------------------------------------------------+

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:19 pm
by PTScalper
Plus i have prepared versions for MT5 traders plus IC traders as well.

Transitioning from MQL4 to MQL5 requires a significant architectural shift. While MQL4 is highly procedural and treats everything as an "order," MQL5 is an object-oriented language that strictly separates Orders (requests to the broker), Deals (historical executions), and Positions (your current open exposure).

Since you are running this on IC Markets (IC Trader), the environment will almost certainly feature 5-digit fractional pricing and raw spreads.

To handle the complex MqlTradeRequest structures cleanly, this MT5 version utilizes the standard MQL5 #include <Trade\Trade.mqh> library. This wraps the execution logic into a robust, object-oriented CTrade class, handling slippage, re-quotes, and server routing natively.

MQL5 Source Code: Liquidity Sweep Auto-Scalper (MT5)

Code: Select all

//+------------------------------------------------------------------+
//|                                   Liquidity_Sweep_Scalper_EA.mq5 |
//|                 Automated Execution with Dynamic Trailing Stop   |
//|                 Optimized for MetaTrader 5 (IC Markets)          |
//+------------------------------------------------------------------+
#property copyright "Automated Zone Scalper EA MT5"
#property version   "1.20"

#include <Trade\Trade.mqh>

// Initialize the Trade Object
CTrade trade;

// --- Trading Parameters ---
input double InpLotSize = 0.10;            // Fixed Lot Size
input int    InpStopLossPips = 5;          // Initial Stop Loss (Pips)
input int    InpTakeProfitPips = 10;       // Take Profit (Pips)
input int    InpMaxSlippage = 3;           // Max Slippage (Pips)
input ulong  InpMagicNumber = 999111;      // EA Identifier (ulong in MT5)

// --- Trailing Stop Parameters ---
input bool   InpUseTrailingStop = true;    // Enable Trailing Stop
input int    InpTrailingStopPips = 4;      // Distance behind price (Pips)
input int    InpTrailingStepPips = 1;      // Minimum move before adjusting (Pips)

// --- Zone Parameters ---
input int    InpLookbackBars = 40;         // Lookback Period (Bars)
input int    InpZoneWidthPips = 2;         // Zone Depth (Pips)
input color  InpSweepHighColor = clrLightCoral;
input color  InpSweepLowColor = clrLightGreen;

//+------------------------------------------------------------------+
int OnInit()
  {
   if(InpStopLossPips <= 0 || InpTakeProfitPips <= 0)
     {
      Print("Invalid SL/TP configuration.");
      return(INIT_PARAMETERS_INCORRECT);
     }
     
   // Configure the CTrade object
   trade.SetExpertMagicNumber(InpMagicNumber);
   trade.SetDeviationInPoints(InpMaxSlippage * ((_Digits == 3 || _Digits == 5) ? 10 : 1));
   
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, "LiqPool_");
  }

void OnTick()
  {
   // 1. Data Retrieval (MQL5 requires copying timeseries data to arrays)
   double High[], Low[], Close[];
   datetime Time[];
   
   // Set arrays to behave like MQL4 (Index 0 = Current Bar)
   ArraySetAsSeries(High, true);
   ArraySetAsSeries(Low, true);
   ArraySetAsSeries(Close, true);
   ArraySetAsSeries(Time, true);
   
   if(CopyHigh(_Symbol, _Period, 0, InpLookbackBars, High) < InpLookbackBars) return;
   if(CopyLow(_Symbol, _Period, 0, InpLookbackBars, Low) < InpLookbackBars) return;
   if(CopyClose(_Symbol, _Period, 0, 1, Close) < 1) return;
   if(CopyTime(_Symbol, _Period, 0, InpLookbackBars, Time) < InpLookbackBars) return;

   // 2. Calculate Pricing Variables
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double pip_size = (_Digits == 3 || _Digits == 5) ? 10.0 * point : point;

   // 3. Manage Open Positions (Trailing Stop)
   if(InpUseTrailingStop)
     {
      ManageTrailingStops(pip_size);
     }

   // 4. State Management: Prevent multiple entries
   if(HasOpenPositions(InpMagicNumber)) return; 

   // 5. Identify Market Structure Extremes
   int highest_idx = ArrayMaximum(High, 0, InpLookbackBars);
   int lowest_idx  = ArrayMinimum(Low, 0, InpLookbackBars);
   
   double swing_high = High[highest_idx];
   double swing_low  = Low[lowest_idx];
   
   double zone_height = InpZoneWidthPips * pip_size;
   double sell_zone_bottom = swing_high - zone_height;
   double buy_zone_top = swing_low + zone_height;

   // 6. Render GUI
   DrawZone("LiqPool_High", Time[highest_idx], swing_high, TimeCurrent() + PeriodSeconds()*10, sell_zone_bottom, InpSweepHighColor);
   DrawZone("LiqPool_Low", Time[lowest_idx], swing_low, TimeCurrent() + PeriodSeconds()*10, buy_zone_top, InpSweepLowColor);

   // 7. Execution Logic
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   // SELL Condition
   if(Close[0] >= sell_zone_bottom && Close[0] <= swing_high)
     {
      double sl = NormalizeDouble(bid + (InpStopLossPips * pip_size), _Digits);
      double tp = NormalizeDouble(bid - (InpTakeProfitPips * pip_size), _Digits);
      
      trade.Sell(InpLotSize, _Symbol, bid, sl, tp, "Liq Sweep Sell");
     }
     
   // BUY Condition
   else if(Close[0] <= buy_zone_top && Close[0] >= swing_low)
     {
      double sl = NormalizeDouble(ask - (InpStopLossPips * pip_size), _Digits);
      double tp = NormalizeDouble(ask + (InpTakeProfitPips * pip_size), _Digits);
      
      trade.Buy(InpLotSize, _Symbol, ask, sl, tp, "Liq Sweep Buy");
     }
  }

//+------------------------------------------------------------------+
//| Subroutine: Manage Dynamic Trailing Stops (MT5 Positions)        |
//+------------------------------------------------------------------+
void ManageTrailingStops(double pip_size)
  {
   double trailing_dist = InpTrailingStopPips * pip_size;
   double trailing_step = InpTrailingStepPips * pip_size;
   
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i); // Selects the position
      
      if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
        {
         double current_sl = PositionGetDouble(POSITION_SL);
         double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
         
         // Manage BUY Position
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
           {
            double current_bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            double new_sl = NormalizeDouble(current_bid - trailing_dist, _Digits);
            
            if(current_bid - open_price > trailing_dist)
              {
               if(current_sl < new_sl - trailing_step || current_sl == 0)
                 {
                  trade.PositionModify(ticket, new_sl, PositionGetDouble(POSITION_TP));
                 }
              }
           }
           
         // Manage SELL Position
         else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
           {
            double current_ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            double new_sl = NormalizeDouble(current_ask + trailing_dist, _Digits);
            
            if(open_price - current_ask > trailing_dist)
              {
               if(current_sl > new_sl + trailing_step || current_sl == 0)
                 {
                  trade.PositionModify(ticket, new_sl, PositionGetDouble(POSITION_TP));
                 }
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Helper: Check if EA has open positions                           |
//+------------------------------------------------------------------+
bool HasOpenPositions(ulong magic_num)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if(PositionGetSymbol(i) == _Symbol)
        {
         if(PositionGetInteger(POSITION_MAGIC) == magic_num) return true;
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Helper: Manage GUI objects                                       |
//+------------------------------------------------------------------+
void DrawZone(string obj_name, datetime t1, double p1, datetime t2, double p2, color clr)
  {
   if(ObjectFind(0, obj_name) < 0)
     {
      ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, t1, p1, t2, p2);
      ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clr);
      ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);
      ObjectSetInteger(0, obj_name, OBJPROP_FILL, true);
      ObjectSetInteger(0, obj_name, OBJPROP_HIDDEN, true);
     }
   else
     {
      ObjectSetInteger(0, obj_name, OBJPROP_TIME1, t1);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE1, p1);
      ObjectSetInteger(0, obj_name, OBJPROP_TIME2, t2);
      ObjectSetDouble(0, obj_name, OBJPROP_PRICE2, p2);
     }
  }
//+------------------------------------------------------------------+
Key Changes for MT5 Architecture#include <Trade\Trade.mqh>: This removes the need for manual OrderSend structures and error logging, replacing them with trade.Buy(), trade.Sell(), and trade.PositionModify().Time Series Arrays: MT5 does not provide direct global access to High[], Low[], or Close[]. We instantiate local arrays on every tick and use CopyHigh, CopyLow, etc., to populate them. ArraySetAsSeries(..., true) is critical here; without it, index 0 would be the oldest bar on the chart, not the newest.Positions vs. Orders: The iteration loops inside HasOpenPositions and ManageTrailingStops have been rewritten to use PositionsTotal() and PositionGetTicket().Variable Typing: Variables like InpMagicNumber and ticket are updated to ulong (Unsigned Long), which is MT5's standard for ticket IDs and Magic Numbers.1.Open MetaEditor 5:Press F4 in your MT5 terminal to open the IDE.2.Create Expert Advisor:Select "New" -> "Expert Advisor (template)", name it Liquidity_Sweep_Scalper_MT5, and click Finish.3.Compile Code:Paste the provided C++ code and press F7 to compile.4.Enable Algo Trading:In your MT5 terminal, ensure the "Algo Trading" button on the top toolbar is pressed (it should turn green), then drag the EA onto your chart.

Re: 1 minute forex scalping strategy without indicators

Posted: Mon Aug 03, 2026 2:22 pm
by PTScalper
And here it is for IC traders:

While MetaTrader uses MQL4/MQL5, cTrader's algorithmic trading engine (cTrader Automate) is built entirely on C#. It is a modern, object-oriented framework that is much faster and cleaner than MetaTrader, especially when handling things like volume normalization and UI drawing.

In cTrader, we don't use "Magic Numbers" to track trades; we use string Labels. Furthermore, cTrader handles lot-to-volume conversions natively, so we don't need complex normalizations to avoid broker rejections.

Here is the exact same 1-minute liquidity sweep strategy, fully translated into a C# cBot for cTrader:

cTrader Automate Source Code (C#)

Code: Select all

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class LiquiditySweepScalper : Robot
    {
        // --- Trading Parameters ---
        [Parameter("Lot Size", DefaultValue = 0.1, MinValue = 0.01)]
        public double LotSize { get; set; }

        [Parameter("Stop Loss (Pips)", DefaultValue = 5)]
        public double StopLossPips { get; set; }

        [Parameter("Take Profit (Pips)", DefaultValue = 10)]
        public double TakeProfitPips { get; set; }

        // --- Trailing Stop Parameters ---
        [Parameter("Enable Trailing Stop", DefaultValue = true, Group = "Trailing Stop")]
        public bool UseTrailingStop { get; set; }

        [Parameter("Trailing Stop (Pips)", DefaultValue = 4, Group = "Trailing Stop")]
        public double TrailingStopPips { get; set; }

        [Parameter("Trailing Step (Pips)", DefaultValue = 1, Group = "Trailing Stop")]
        public double TrailingStepPips { get; set; }

        // --- Zone Parameters ---
        [Parameter("Lookback Period (Bars)", DefaultValue = 40, Group = "Zones")]
        public int LookbackBars { get; set; }

        [Parameter("Zone Depth (Pips)", DefaultValue = 2.0, Group = "Zones")]
        public double ZoneWidthPips { get; set; }

        private readonly string _botLabel = "LiqSweepBot";

        protected override void OnStart()
        {
            // Fired when the bot starts
            Print("Liquidity Sweep Scalper Initialized on {0}", SymbolName);
        }

        protected override void OnTick()
        {
            // Ensure enough data is loaded
            if (Bars.Count < LookbackBars) return;

            // 1. Manage Trailing Stops on every tick
            if (UseTrailingStop)
            {
                ManageTrailingStops();
            }

            // 2. State Management: Prevent overlapping positions
            if (Positions.Count(x => x.Label == _botLabel && x.SymbolName == SymbolName) > 0)
                return;

            // 3. Find Market Structure Extremes
            double swingHigh = double.MinValue;
            double swingLow = double.MaxValue;
            int highestIdx = 0;
            int lowestIdx = 0;

            for (int i = 1; i <= LookbackBars; i++)
            {
                double high = Bars.HighPrices.Last(i);
                double low = Bars.LowPrices.Last(i);
                
                if (high > swingHigh)
                {
                    swingHigh = high;
                    highestIdx = i;
                }
                if (low < swingLow)
                {
                    swingLow = low;
                    lowestIdx = i;
                }
            }

            double zoneHeight = ZoneWidthPips * Symbol.PipSize;
            double sellZoneBottom = swingHigh - zoneHeight;
            double buyZoneTop = swingLow + zoneHeight;

            // 4. Render GUI Zones (Semi-transparent rectangles)
            DateTime highTime = Bars.OpenTimes.Last(highestIdx);
            DateTime lowTime = Bars.OpenTimes.Last(lowestIdx);
            DateTime futureTime = Server.Time.AddMinutes(10); // Extend boxes 10 mins forward

            Chart.DrawRectangle("LiqPool_High", highTime, swingHigh, futureTime, sellZoneBottom, Color.FromArgb(70, Color.LightCoral)).IsFilled = true;
            Chart.DrawRectangle("LiqPool_Low", lowTime, swingLow, futureTime, buyZoneTop, Color.FromArgb(70, Color.LightGreen)).IsFilled = true;

            // 5. Execution Logic
            double currentClose = Bars.ClosePrices.Last(0);
            double volumeInUnits = Symbol.QuantityToVolumeInUnits(LotSize);

            // SELL Condition
            if (currentClose >= sellZoneBottom && currentClose <= swingHigh)
            {
                ExecuteMarketOrder(TradeType.Sell, SymbolName, volumeInUnits, _botLabel, StopLossPips, TakeProfitPips);
            }
            // BUY Condition
            else if (currentClose <= buyZoneTop && currentClose >= swingLow)
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, volumeInUnits, _botLabel, StopLossPips, TakeProfitPips);
            }
        }

        // --- Subroutine: Manage Dynamic Trailing Stops ---
        private void ManageTrailingStops()
        {
            var activePositions = Positions.FindAll(_botLabel, SymbolName);
            
            foreach (var position in activePositions)
            {
                if (position.TradeType == TradeType.Buy)
                {
                    double newSl = Symbol.Bid - (TrailingStopPips * Symbol.PipSize);
                    
                    // Check if price moved into profit by trailing distance
                    if (Symbol.Bid - position.EntryPrice >= TrailingStopPips * Symbol.PipSize)
                    {
                        if (position.StopLoss == null || position.StopLoss < newSl - (TrailingStepPips * Symbol.PipSize))
                        {
                            ModifyPosition(position, Math.Round(newSl, Symbol.Digits), position.TakeProfit);
                        }
                    }
                }
                else if (position.TradeType == TradeType.Sell)
                {
                    double newSl = Symbol.Ask + (TrailingStopPips * Symbol.PipSize);
                    
                    if (position.EntryPrice - Symbol.Ask >= TrailingStopPips * Symbol.PipSize)
                    {
                        if (position.StopLoss == null || position.StopLoss > newSl + (TrailingStepPips * Symbol.PipSize))
                        {
                            ModifyPosition(position, Math.Round(newSl, Symbol.Digits), position.TakeProfit);
                        }
                    }
                }
            }
        }
    }
}
Setup Instructions for cTrader

1.Open cTrader Automate:In your IC Markets cTrader platform, click on the Automate tab (the robot icon) on the left-hand sidebar.

2.Create a New cBot:Click the + New cBot button at the top of the list. Name it LiquiditySweepScalper.

3.Paste and Build:Replace all the default template code in the central editor with the C# code above. Click the Build button (hammer icon) at the top of the editor. If successful, you'll see a green "Build Succeeded" message.

4.Add an Instance:Click the + button next to your bot's name in the left menu to add an instance for a specific chart (e.g., EURUSD m1). Adjust your lot sizing in the parameters panel, and click the Play button to activate it.

Take a care and have a lot of scalps,
Bye bye

And if you have some improvments or any other ideas, let me know :-)
Share it with us here.