Advertisement IC Markets

The 60-Second Trader: Why Pair Selection is Your Biggest Edge in Forex Scalping

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: The 60-Second Trader: Why Pair Selection is Your Biggest Edge in Forex Scalping

Post by PTScalper »

The Institutional Differences

The Thick Orange Line (Macro Trend): You will now see a thick orange line on your 1-minute chart. This is the exact location of the 15-minute 200 EMA. The script guarantees you are never fighting the higher timeframe flow. If the 1m chart drops below its moving averages but the price is still above the 15m orange line, the script ignores the short signal.

Embedded Reality Checks: In the first line (strategy(...)), I added commission_value=3.0 (simulating a standard $6 round-turn per lot) and slippage=2 (simulating 2 ticks of slippage on every entry and exit). This will make your backtesting curve look significantly more realistic—and likely rougher. This is a good thing; it forces you to optimize for reality, not fantasy.

The "Halted" State: If you look at the bottom right HUD, you will see a Circuit Breaker status. If you suffer three 1% losses in a single day, the daily PnL will hit -3%. The breaker status will flip to 🔴 HALTED, and the algorithm will instantly shut off order flow until the midnight daily reset. This physically stops "revenge trading" algorithms from burning your capital.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: The 60-Second Trader: Why Pair Selection is Your Biggest Edge in Forex Scalping

Post by PTScalper »

To run this strategy on MetaTrader 4 and 5 with institutional execution, the logic must handle broker-side mechanics that TradingView abstracts away: broker server time offsets, dynamic pip scaling for 3/5-digit quotes, tick-value normalization for lot sizing, and multi-timeframe handle buffers.

Below are the complete, compilation-ready Expert Advisors (EAs) for both MT5 (MQL5) and MT4 (MQL4).

1. MT5 Expert Advisor (EliteScalper_MT5.mq5)

MT5 utilizes the modern event-driven MQL5 architecture with #include <Trade\Trade.mqh>, non-repainting indicator handles, and native microsecond execution.

Code: Select all

//+------------------------------------------------------------------+
//|                                             EliteScalper_MT5.mq5 |
//|                                  London / New York Overlap Engine|
//+------------------------------------------------------------------+
#property copyright "Elite Scalper Systems"
#property link      "https://www.mql5.com"
#property version   "2.00"
#property strict

#include <Trade\Trade.mqh>

//--- Input Parameters
input group "--- Risk & Account Management ---"
input double   InpRiskPercent       = 1.0;       // Risk Per Trade (% of Equity)
input double   InpMaxDailyLossPct   = 3.0;       // Circuit Breaker: Max Daily Loss (%)
input double   InpMaxDailyProfitPct = 5.0;       // Circuit Breaker: Max Daily Profit (%)
input double   InpStopLossPips      = 5.0;       // Stop Loss (Pips)
input double   InpTakeProfitPips    = 8.0;       // Take Profit (Pips)
input ulong    InpMagicNumber       = 109202;    // Magic Number

input group "--- Session Filter (Broker Server Time) ---"
input int      InpStartHour         = 15;        // Session Start Hour (e.g. 08:00 EST in Broker Time)
input int      InpStartMinute       = 0;         // Session Start Minute
input int      InpEndHour           = 19;        // Session End Hour (e.g. 12:00 EST in Broker Time)
input int      InpEndMinute         = 0;         // Session End Minute
input bool     InpCloseOnSessionEnd = true;      // Liquidate Positions at Session End

input group "--- Institutional Filters ---"
input ENUM_TIMEFRAMES InpMacroTf    = PERIOD_M15;// Macro Trend Timeframe
input int      InpMacroEmaPeriod    = 200;       // Macro EMA Period
input int      InpFastEmaPeriod     = 9;         // Micro Fast EMA (M1)
input int      InpSlowEmaPeriod     = 21;        // Micro Slow EMA (M1)
input double   InpMinAtrPips        = 2.0;       // Min ATR Volatility (Pips)
input int      InpAtrPeriod         = 14;        // ATR Period

//--- Internal State
CTrade         trade;
int            hFastEma, hSlowEma, hMacroEma, hAtr;
double         pipSize;
datetime       currentDay;
double         dayStartBalance;
bool           circuitBreakerHit;

//+------------------------------------------------------------------+
//| Expert Initialization                                            |
//+------------------------------------------------------------------+
int OnInit()
{
   trade.SetExpertMagicNumber(InpMagicNumber);
   trade.SetMarginMode();
   trade.SetTypeFillingBySymbol(_Symbol);

   // Determine Pip Size for 3/5 digit broker quotes
   pipSize = (_Digits == 3 || _Digits == 5) ? _Point * 10.0 : _Point;

   // Initialize Indicator Handles
   hFastEma  = iMA(_Symbol, PERIOD_CURRENT, InpFastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
   hSlowEma  = iMA(_Symbol, PERIOD_CURRENT, InpSlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
   hMacroEma = iMA(_Symbol, InpMacroTf, InpMacroEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
   hAtr      = iATR(_Symbol, PERIOD_CURRENT, InpAtrPeriod);

   if(hFastEma == INVALID_HANDLE || hSlowEma == INVALID_HANDLE || 
      hMacroEma == INVALID_HANDLE || hAtr == INVALID_HANDLE)
   {
      Print("Error initializing indicator handles.");
      return INIT_FAILED;
   }

   currentDay        = 0;
   dayStartBalance   = AccountInfoDouble(ACCOUNT_BALANCE);
   circuitBreakerHit = false;

   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert Deinitialization                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   IndicatorRelease(hFastEma);
   IndicatorRelease(hSlowEma);
   IndicatorRelease(hMacroEma);
   IndicatorRelease(hAtr);
   Comment("");
}

//+------------------------------------------------------------------+
//| Dynamic Position Sizing (Strict Risk-to-Lot Algorithm)          |
//+------------------------------------------------------------------+
double CalculateLotSize(double slPips)
{
   double equity      = AccountInfoDouble(ACCOUNT_EQUITY);
   double riskAmount  = equity * (InpRiskPercent / 100.0);
   double tickSize    = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue   = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   
   if(tickSize <= 0 || tickValue <= 0) return 0.0;
   
   double slPriceDist = slPips * pipSize;
   double riskPerLot  = (slPriceDist / tickSize) * tickValue;
   
   if(riskPerLot <= 0) return 0.0;
   
   double calculatedLot = riskAmount / riskPerLot;
   
   // Align to Broker Constraints
   double minLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   
   calculatedLot = MathFloor(calculatedLot / stepLot) * stepLot;
   return MathMin(MathMax(calculatedLot, minLot), maxLot);
}

//+------------------------------------------------------------------+
//| Execution Utilities                                              |
//+------------------------------------------------------------------+
bool IsInSession()
{
   MqlDateTime dt;
   TimeCurrent(dt);
   int curMin   = dt.hour * 60 + dt.min;
   int startMin = InpStartHour * 60 + InpStartMinute;
   int endMin   = InpEndHour * 60 + InpEndMinute;

   return (startMin <= endMin) ? (curMin >= startMin && curMin < endMin) 
                               : (curMin >= startMin || curMin < endMin);
}

int CountOpenPositions()
{
   int count = 0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(PositionGetTicket(i) > 0)
      {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol && 
            PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
            count++;
      }
   }
   return count;
}

void CloseAllPositions(string reason)
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol && 
         PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
      {
         trade.PositionClose(ticket);
         Print("Closed Position #", ticket, " Reason: ", reason);
      }
   }
}

//+------------------------------------------------------------------+
//| Expert Tick Function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Daily Midnight Reset for Circuit Breaker
   MqlDateTime dt;
   TimeCurrent(dt);
   datetime today = StringToTime(StringFormat("%04d.%02d.%02d 00:00", dt.year, dt.mon, dt.day));
   
   if(today != currentDay)
   {
      currentDay        = today;
      dayStartBalance   = AccountInfoDouble(ACCOUNT_BALANCE);
      circuitBreakerHit = false;
   }

   // Circuit Breaker Calculation
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double pnlPct = ((equity - dayStartBalance) / dayStartBalance) * 100.0;
   
   if(!circuitBreakerHit && (pnlPct <= -InpMaxDailyLossPct || pnlPct >= InpMaxDailyProfitPct))
   {
      circuitBreakerHit = true;
      CloseAllPositions("Circuit Breaker Tripped");
   }

   bool sessionActive = IsInSession();

   // End-of-Session Auto Close
   if(!sessionActive && InpCloseOnSessionEnd && CountOpenPositions() > 0)
   {
      CloseAllPositions("End of Trading Session");
   }

   // Buffer Reads
   double fast[2], slow[2], macro[1], atr[1];
   if(CopyBuffer(hFastEma, 0, 0, 2, fast) < 2 ||
      CopyBuffer(hSlowEma, 0, 0, 2, slow) < 2 ||
      CopyBuffer(hMacroEma, 0, 0, 1, macro) < 1 ||
      CopyBuffer(hAtr, 0, 0, 1, atr) < 1)
      return;

   double currentAtrPips = atr[0] / pipSize;
   bool volatilityOk     = (currentAtrPips >= InpMinAtrPips);
   double ask            = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid            = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   bool macroBull        = (bid > macro[0]);
   bool macroBear        = (ask < macro[0]);

   // Terminal Dashboard
   string hud = StringFormat(
      "=== ELITE SCALPER HUD (MT5) ===\n" +
      "Session Status: %s\n" +
      "Circuit Breaker: %s (Daily PnL: %.2f%%)\n" +
      "Volatility: %.2f Pips (Min: %.1f)\n" +
      "Macro Trend (15M): %s\n" +
      "Active Positions: %d",
      sessionActive ? "ACTIVE" : "CLOSED",
      circuitBreakerHit ? "LOCKED" : "CLEAR", pnlPct,
      currentAtrPips, InpMinAtrPips,
      macroBull ? "BULLISH" : macroBear ? "BEARISH" : "FLAT",
      CountOpenPositions()
   );
   Comment(hud);

   // Order Execution Gate
   if(!sessionActive || circuitBreakerHit || CountOpenPositions() > 0 || !volatilityOk)
      return;

   // Momentum Crossover Triggers
   bool buySignal  = (fast[1] <= slow[1] && fast[0] > slow[0]) && macroBull;
   bool sellSignal = (fast[1] >= slow[1] && fast[0] < slow[0]) && macroBear;

   if(buySignal)
   {
      double lot = CalculateLotSize(InpStopLossPips);
      double sl  = ask - (InpStopLossPips * pipSize);
      double tp  = ask + (InpTakeProfitPips * pipSize);
      trade.Buy(lot, _Symbol, ask, sl, tp, "Elite Scalper Long");
   }
   else if(sellSignal)
   {
      double lot = CalculateLotSize(InpStopLossPips);
      double sl  = bid + (InpStopLossPips * pipSize);
      double tp  = bid - (InpTakeProfitPips * pipSize);
      trade.Sell(lot, _Symbol, bid, sl, tp, "Elite Scalper Short");
   }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: The 60-Second Trader: Why Pair Selection is Your Biggest Edge in Forex Scalping

Post by PTScalper »

2. MT4 Expert Advisor (EliteScalper_MT4.mq4)

MT4 relies on the MQL4 execution model. This code handles OrderSend execution, point/pip conversions for 5-digit brokers, MTF calculations via direct runtime functions, and manual ticket-by-ticket position iteration.

Code: Select all

//+------------------------------------------------------------------+
//|                                             EliteScalper_MT4.mq4 |
//|                                  London / New York Overlap Engine|
//+------------------------------------------------------------------+
#property copyright "Elite Scalper Systems"
#property link      "https://www.mql5.com"
#property version   "2.00"
#property strict

//--- Input Parameters
input string   RiskHeader           = "--- Risk & Account Management ---";
input double   InpRiskPercent       = 1.0;       // Risk Per Trade (% of Equity)
input double   InpMaxDailyLossPct   = 3.0;       // Circuit Breaker: Max Daily Loss (%)
input double   InpMaxDailyProfitPct = 5.0;       // Circuit Breaker: Max Daily Profit (%)
input double   InpStopLossPips      = 5.0;       // Stop Loss (Pips)
input double   InpTakeProfitPips    = 8.0;       // Take Profit (Pips)
input int      InpMagicNumber       = 109202;    // Magic Number

input string   SessionHeader        = "--- Session Filter (Server Time) ---";
input int      InpStartHour         = 15;        // Session Start Hour
input int      InpStartMinute       = 0;         // Session Start Minute
input int      InpEndHour           = 19;        // Session End Hour
input int      InpEndMinute         = 0;         // Session End Minute
input bool     InpCloseOnSessionEnd = true;      // Liquidate at Session End

input string   FilterHeader         = "--- Technical Parameters ---";
input int      InpMacroTf           = 15;        // Macro Trend Timeframe (Minutes)
input int      InpMacroEmaPeriod    = 200;       // Macro EMA Period
input int      InpFastEmaPeriod     = 9;         // Micro Fast EMA (M1)
input int      InpSlowEmaPeriod     = 21;        // Micro Slow EMA (M1)
input double   InpMinAtrPips        = 2.0;       // Min ATR Volatility (Pips)
input int      InpAtrPeriod         = 14;        // ATR Period

//--- Internal State
double   pipSize;
datetime currentDay;
double   dayStartBalance;
bool     circuitBreakerHit;

//+------------------------------------------------------------------+
//| Expert Initialization                                            |
//+------------------------------------------------------------------+
int OnInit()
{
   pipSize = (_Digits == 3 || _Digits == 5) ? _Point * 10.0 : _Point;
   currentDay        = 0;
   dayStartBalance   = AccountBalance();
   circuitBreakerHit = false;
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   Comment("");
}

//+------------------------------------------------------------------+
//| Dynamic Lot Size Calculation                                     |
//+------------------------------------------------------------------+
double CalculateLotSize(double slPips)
{
   double equity      = AccountEquity();
   double riskAmount  = equity * (InpRiskPercent / 100.0);
   double tickValue   = MarketInfo(_Symbol, MODE_TICKVALUE);
   double tickSize    = MarketInfo(_Symbol, MODE_TICKSIZE);

   if(tickSize <= 0 || tickValue <= 0) return 0.0;

   double slPriceDist = slPips * pipSize;
   double riskPerLot  = (slPriceDist / tickSize) * tickValue;

   if(riskPerLot <= 0) return 0.0;

   double calculatedLot = riskAmount / riskPerLot;
   double minLot  = MarketInfo(_Symbol, MODE_MINLOT);
   double maxLot  = MarketInfo(_Symbol, MODE_MAXLOT);
   double stepLot = MarketInfo(_Symbol, MODE_LOTSTEP);

   calculatedLot = MathFloor(calculatedLot / stepLot) * stepLot;
   return MathMin(MathMax(calculatedLot, minLot), maxLot);
}

//+------------------------------------------------------------------+
//| Execution State Utilities                                        |
//+------------------------------------------------------------------+
bool IsInSession()
{
   int curMin   = TimeHour(TimeCurrent()) * 60 + TimeMinute(TimeCurrent());
   int startMin = InpStartHour * 60 + InpStartMinute;
   int endMin   = InpEndHour * 60 + InpEndMinute;

   return (startMin <= endMin) ? (curMin >= startMin && curMin < endMin) 
                               : (curMin >= startMin || curMin < endMin);
}

int CountOpenPositions()
{
   int count = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
            count++;
      }
   }
   return count;
}

void CloseAllPositions(string reason)
{
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagicNumber)
         {
            int ticket = OrderTicket();
            double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
            bool res = OrderClose(ticket, OrderLots(), closePrice, 3, clrRed);
            if(res) Print("Closed Order #", ticket, " Reason: ", reason);
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Expert Tick Function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Daily Circuit Breaker Tracking
   datetime today = iTime(_Symbol, PERIOD_D1, 0);
   if(today != currentDay)
   {
      currentDay        = today;
      dayStartBalance   = AccountBalance();
      circuitBreakerHit = false;
   }

   double equity = AccountEquity();
   double pnlPct = ((equity - dayStartBalance) / dayStartBalance) * 100.0;

   if(!circuitBreakerHit && (pnlPct <= -InpMaxDailyLossPct || pnlPct >= InpMaxDailyProfitPct))
   {
      circuitBreakerHit = true;
      CloseAllPositions("Circuit Breaker Tripped");
   }

   bool sessionActive = IsInSession();

   // End-of-Session Liquidation
   if(!sessionActive && InpCloseOnSessionEnd && CountOpenPositions() > 0)
   {
      CloseAllPositions("End of Trading Session");
   }

   // Technical Calculations
   double fastCurrent = iMA(_Symbol, PERIOD_M1, InpFastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
   double fastPrev    = iMA(_Symbol, PERIOD_M1, InpFastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
   double slowCurrent = iMA(_Symbol, PERIOD_M1, InpSlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);
   double slowPrev    = iMA(_Symbol, PERIOD_M1, InpSlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);

   // MTF Higher Timeframe Read (15m Macro Trend)
   double macroEma    = iMA(_Symbol, InpMacroTf, InpMacroEmaPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);

   // Volatility Filter
   double atrValue       = iATR(_Symbol, PERIOD_M1, InpAtrPeriod, 0);
   double currentAtrPips = atrValue / pipSize;
   bool volatilityOk     = (currentAtrPips >= InpMinAtrPips);

   bool macroBull = (Bid > macroEma);
   bool macroBear = (Ask < macroEma);

   // On-Chart HUD
   string hud = StringFormat(
      "=== ELITE SCALPER HUD (MT4) ===\n" +
      "Session Status: %s\n" +
      "Circuit Breaker: %s (Daily PnL: %.2f%%)\n" +
      "Volatility: %.2f Pips (Min: %.1f)\n" +
      "Macro Trend (15M): %s\n" +
      "Open Positions: %d",
      sessionActive ? "ACTIVE" : "CLOSED",
      circuitBreakerHit ? "LOCKED" : "CLEAR", pnlPct,
      currentAtrPips, InpMinAtrPips,
      macroBull ? "BULLISH" : macroBear ? "BEARISH" : "FLAT",
      CountOpenPositions()
   );
   Comment(hud);

   // Gate Checks
   if(!sessionActive || circuitBreakerHit || CountOpenPositions() > 0 || !volatilityOk)
      return;

   // Micro Crossovers
   bool buySignal  = (fastPrev <= slowPrev && fastCurrent > slowCurrent) && macroBull;
   bool sellSignal = (fastPrev >= slowPrev && fastCurrent < slowCurrent) && macroBear;

   if(buySignal)
   {
      double lot = CalculateLotSize(InpStopLossPips);
      double sl  = NormalizeDouble(Ask - (InpStopLossPips * pipSize), _Digits);
      double tp  = NormalizeDouble(Ask + (InpTakeProfitPips * pipSize), _Digits);
      int ticket = OrderSend(_Symbol, OP_BUY, lot, Ask, 3, sl, tp, "Elite Scalper", InpMagicNumber, 0, clrBlue);
   }
   else if(sellSignal)
   {
      double lot = CalculateLotSize(InpStopLossPips);
      double sl  = NormalizeDouble(Bid + (InpStopLossPips * pipSize), _Digits);
      double tp  = NormalizeDouble(Bid - (InpTakeProfitPips * pipSize), _Digits);
      int ticket = OrderSend(_Symbol, OP_SELL, lot, Bid, 3, sl, tp, "Elite Scalper", InpMagicNumber, 0, clrRed);
   }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: The 60-Second Trader: Why Pair Selection is Your Biggest Edge in Forex Scalping

Post by PTScalper »

The shift to cTrader is an excellent choice for a professional scalper. Unlike MetaTrader, cTrader was built specifically for ECN (Electronic Communication Network) and STP (Straight Through Processing) environments. It natively executes in microseconds, utilizes FIX API for instant routing, and has a vastly superior volume-calculation engine built right in.

Below is the complete C# cBot source code for the Elite Scalper Engine using the cTrader Automate API.

The Elite Scalper cBot (C# for cTrader)

Code: Select all

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class EliteScalper_cBot : Robot
    {
        // =========================================================================
        // 1. RISK & ACCOUNT MANAGEMENT
        // =========================================================================
        [Parameter("Risk Per Trade (%)", Group = "Risk Management", DefaultValue = 1.0, MinValue = 0.1)]
        public double RiskPercent { get; set; }

        [Parameter("Max Daily Loss (%)", Group = "Risk Management", DefaultValue = 3.0)]
        public double MaxDailyLossPct { get; set; }

        [Parameter("Max Daily Profit (%)", Group = "Risk Management", DefaultValue = 5.0)]
        public double MaxDailyProfitPct { get; set; }

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

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

        // =========================================================================
        // 2. TIMING & SESSION (Strict UTC Times to ignore Broker Offsets)
        // =========================================================================
        [Parameter("Session Start Hour (UTC)", Group = "Session Settings", DefaultValue = 13)]
        public int SessionStartHour { get; set; }

        [Parameter("Session End Hour (UTC)", Group = "Session Settings", DefaultValue = 17)]
        public int SessionEndHour { get; set; }

        [Parameter("Close on Session End", Group = "Session Settings", DefaultValue = true)]
        public bool CloseOnSessionEnd { get; set; }

        // =========================================================================
        // 3. ELITE FILTERS: MTF TREND & VOLATILITY
        // =========================================================================
        [Parameter("Macro Timeframe", Group = "Institutional Filters", DefaultValue = "Minute15")]
        public TimeFrame MacroTf { get; set; }

        [Parameter("Macro EMA Period", Group = "Institutional Filters", DefaultValue = 200)]
        public int MacroEmaPeriod { get; set; }

        [Parameter("Fast EMA Period", Group = "Institutional Filters", DefaultValue = 9)]
        public int FastEmaPeriod { get; set; }

        [Parameter("Slow EMA Period", Group = "Institutional Filters", DefaultValue = 21)]
        public int SlowEmaPeriod { get; set; }

        [Parameter("Min ATR (Pips)", Group = "Institutional Filters", DefaultValue = 2.0)]
        public double MinAtrPips { get; set; }

        // =========================================================================
        // INTERNAL STATE & INDICATORS
        // =========================================================================
        private ExponentialMovingAverage _fastEma;
        private ExponentialMovingAverage _slowEma;
        private ExponentialMovingAverage _macroEma;
        private AverageTrueRange _atr;
        private Bars _macroBars;
        
        private string _botLabel = "Elite Scalper";
        private DateTime _currentDay;
        private double _dayStartBalance;
        private bool _circuitBreakerHit;

        protected override void OnStart()
        {
            // Initialize Multi-Timeframe Data
            _macroBars = MarketData.GetBars(MacroTf);

            // Initialize Indicators
            _fastEma = Indicators.ExponentialMovingAverage(Bars.ClosePrices, FastEmaPeriod);
            _slowEma = Indicators.ExponentialMovingAverage(Bars.ClosePrices, SlowEmaPeriod);
            _macroEma = Indicators.ExponentialMovingAverage(_macroBars.ClosePrices, MacroEmaPeriod);
            _atr = Indicators.AverageTrueRange(Bars, 14, MovingAverageType.Simple);

            // Set Day Tracking
            _currentDay = Server.TimeInUtc.Date;
            _dayStartBalance = Account.Balance;
            _circuitBreakerHit = false;
        }

        protected override void OnTick()
        {
            // 1. Daily Reset for Circuit Breaker
            if (Server.TimeInUtc.Date != _currentDay)
            {
                _currentDay = Server.TimeInUtc.Date;
                _dayStartBalance = Account.Balance;
                _circuitBreakerHit = false;
            }

            // 2. Track Circuit Breakers (Daily PnL)
            double pnlPct = ((Account.Equity - _dayStartBalance) / _dayStartBalance) * 100.0;
            if (!_circuitBreakerHit && (pnlPct <= -MaxDailyLossPct || pnlPct >= MaxDailyProfitPct))
            {
                _circuitBreakerHit = true;
                CloseAllPositions("Circuit Breaker Tripped");
            }

            // 3. Session Tracking via UTC Time (Bulletproof against broker server offsets)
            int currentHour = Server.TimeInUtc.Hour;
            bool isSessionActive = (currentHour >= SessionStartHour && currentHour < SessionEndHour);

            if (!isSessionActive && CloseOnSessionEnd && GetActivePositions().Length > 0)
            {
                CloseAllPositions("Session Ended");
            }

            // 4. Update Heads-Up Display (HUD)
            UpdateHUD(isSessionActive, pnlPct);

            // 5. Execution Gates (Halt if out of session, circuit broken, or already in trade)
            if (!isSessionActive || _circuitBreakerHit || GetActivePositions().Length > 0)
                return;

            // 6. Volatility & Macro Trend Filters
            double currentAtrPips = Math.Round(_atr.Result.Last(0) / Symbol.PipSize, 2);
            bool isVolatilityOk = currentAtrPips >= MinAtrPips;

            double macroValue = _macroEma.Result.Last(0);
            bool macroBull = Symbol.Bid > macroValue;
            bool macroBear = Symbol.Ask < macroValue;

            if (!isVolatilityOk) return;

            // 7. Micro Trigger Logic (HasCrossed evaluates the instant tick crossover)
            bool longSignal = _fastEma.Result.HasCrossedAbove(_slowEma.Result, 0) && macroBull;
            bool shortSignal = _fastEma.Result.HasCrossedBelow(_slowEma.Result, 0) && macroBear;

            // 8. Dynamic Volume Execution
            if (longSignal)
            {
                double volume = CalculateVolume(StopLossPips);
                ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, _botLabel, StopLossPips, TakeProfitPips);
            }
            else if (shortSignal)
            {
                double volume = CalculateVolume(StopLossPips);
                ExecuteMarketOrder(TradeType.Sell, SymbolName, volume, _botLabel, StopLossPips, TakeProfitPips);
            }
        }

        // =========================================================================
        // HELPER FUNCTIONS
        // =========================================================================
        
        // Native Institutional Position Sizing Engine
        private double CalculateVolume(double slPips)
        {
            double equityRiskAmount = Account.Equity * (RiskPercent / 100.0);
            
            // cTrader natively knows the exact value of 1 pip for 1 unit of this asset
            double exactVolume = equityRiskAmount / (slPips * Symbol.PipValue);
            
            // Normalize volume to broker's valid step/min limits instantly
            return Symbol.NormalizeVolumeInUnits(exactVolume, RoundingMode.Down);
        }

        private Position[] GetActivePositions()
        {
            return Positions.FindAll(_botLabel, SymbolName);
        }

        private void CloseAllPositions(string reason)
        {
            var positions = GetActivePositions();
            foreach (var pos in positions)
            {
                ClosePosition(pos);
                Print("Position Closed: {0}", reason);
            }
        }

        private void UpdateHUD(bool sessionActive, double dailyPnlPct)
        {
            double currentAtrPips = Math.Round(_atr.Result.Last(0) / Symbol.PipSize, 2);
            string trendStr = Symbol.Bid > _macroEma.Result.Last(0) ? "BULLISH" : "BEARISH";
            
            string hudText = string.Format(
                "=== ELITE SCALPER TERMINAL (cTrader) ===\n" +
                "Session: {0}\n" +
                "Circuit Breaker: {1} (PnL: {2}%)\n" +
                "Volatility: {3} Pips (Min: {4})\n" +
                "15m Macro Trend: {5}",
                sessionActive ? "🟢 ACTIVE" : "🔴 CLOSED",
                _circuitBreakerHit ? "HALTED" : "CLEAR",
                Math.Round(dailyPnlPct, 2),
                currentAtrPips, MinAtrPips,
                trendStr
            );

            Chart.DrawStaticText("QuantHUD", hudText, VerticalAlignment.Bottom, HorizontalAlignment.Right, Color.WhiteSmoke);
        }
    }
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: The 60-Second Trader: Why Pair Selection is Your Biggest Edge in Forex Scalping

Post by PTScalper »

The Institutional cTrader Advantages

Here is why this strategy acts as a significantly sharper weapon in cTrader compared to MT4/MT5 or TradingView:

1. Timezone Bulletproofing (UTC Enforcement):

MT4/MT5 forces you to guess your broker's server time (GMT+2, GMT+3, daylight savings time shifts) which destroys session-dependent EAs if the broker moves their clock.

The Upgrade: I routed the cTrader session logic entirely through Server.TimeInUtc. By using absolute UTC time, 13:00 to 17:00 UTC is always the London/New York overlap, regardless of what broker you use, where you live, or what month it is. It will never fail.

2. Native Pip & Volume Engine:

Calculating precise lot sizes in MQL4/MQL5 requires a massive block of code fetching tick values, checking if the broker is 3-digit, 4-digit, or 5-digit, and normalizing lots.

The Upgrade: cTrader is hyper-modern. The script calculates your exact volume natively using Symbol.PipValue and auto-rounds it perfectly using Symbol.NormalizeVolumeInUnits. If you risk 1%, you will lose exactly 1% down to the cent, without code-bloat.

3. Direct Institutional Tick Data:

Because cTrader was designed for ECNs, the OnTick() loop evaluates crossover momentum (HasCrossedAbove) exactly as the institutional liquidity pools push the tick, without the artificial throttling sometimes seen on retail MT4 bridges.

How to Install and Run in cTrader

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

2.) Click New cBot and name it EliteScalper.

3.) Erase the default code that appears, paste all of the C# code above, and click the Build icon (the hammer) at the top of the screen.

4.) Go back to the Automate menu, click the + next to your new EliteScalper bot to add an instance for your chosen major pair (e.g., EURUSD). Set the timeframe to 1 Minute (m1) and press Play.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply