Advertisement IC Markets

The 5-Minute Chart: The Scalper's Middle Ground

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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

How it executes your philosophy:

The 200 EMA (Thick White Line): Acts as the primary filter. If price is above it, the script ignores all bearish signals. If below, it ignores all bullish signals. This stops you from taking impulsive trades against the dominant momentum.

The 9/21 EMA Cross (Blue/Orange Lines): This provides the "multiple legitimate setups" per session. It lags slightly behind a 1-minute chart, meaning a cross on the 5-minute actually represents confirmed momentum rather than a 30-second fakeout.

ATR Risk Management: By using Average True Range to set targets, the script forces mechanical, thoughtful trade management (a default 1:2 Risk-to-Reward) instead of panic-closing a trade because a 1-minute candle flashed red.
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

To elevate this script from a "beginner's template" to a professional-grade scalping tool, we need to add the mechanics that full-time traders actually use to survive in live markets.

A professional strategy doesn't just look for entries; it focuses heavily on capital preservation, filtering out "chop" (sideways markets), and scaling out of trades.

What makes this version "Pro"?

Dynamic Risk-Based Position Sizing: Instead of using an arbitrary percentage of your account, it calculates your exact lot/position size so you only ever risk exactly 1% (or your chosen amount) of your capital per trade.

The "Chop" Filter (ADX): EMA crosses happen constantly in sideways markets, leading to death by a thousand paper cuts. This version adds the Average Directional Index (ADX) to ensure there is actual momentum before taking a signal.

Partial Take Profits & Breakeven: It automatically sells 50% of your position at a 1:1 risk/reward (TP1) to secure profits, then moves your Stop Loss to breakeven, letting the remaining 50% run "risk-free" to a 1:2 target (TP2).

Session Constraints: Pros don't scalp 24/7. This script restricts trading to high-liquidity hours (e.g., the New York overlap) to avoid low-volume fakeouts.

Heads-Up Display (HUD): A real-time dashboard on your chart showing market state, current ATR, and trend conditions.
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

The Pro 5-Minute Scalper (Pine Script v5)

Code: Select all

//@version=5
strategy("Pro 5-Min Sweet Spot Scalper", overlay=true, initial_capital=10000, commission_type=strategy.commission.percent, commission_value=0.02, calc_on_every_tick=true)

// =========================================================================
// 1. INPUTS: Pro Trade Desk Settings
// =========================================================================
grpRisk   = "1. Risk Management & Sizing"
riskPct   = input.float(1.0, title="Risk Per Trade (%)", group=grpRisk, tooltip="Calculates position size to strictly risk this % of your equity.")
atrLen    = input.int(14, title="ATR Length", group=grpRisk)
slMult    = input.float(1.5, title="Stop Loss ATR Multiplier", step=0.1, group=grpRisk)
tp1Mult   = input.float(1.5, title="TP1 (Scale Out 50%) ATR", step=0.1, group=grpRisk)
tp2Mult   = input.float(3.0, title="TP2 (Runner) ATR", step=0.1, group=grpRisk)

grpTime   = "2. Session Constraints"
useTime   = input.bool(true, title="Enable Session Filter?", group=grpTime)
tradeTime = input.session("0930-1530", title="Trading Hours (Exchange Time)", group=grpTime)

grpTrend  = "3. Trend & Momentum Filters"
fastLen   = input.int(9, title="Fast EMA", group=grpTrend)
slowLen   = input.int(21, title="Slow EMA", group=grpTrend)
trendLen  = input.int(200, title="200 EMA (Macro Trend)", group=grpTrend)
adxThresh = input.int(20, title="ADX Minimum (Chop Filter)", group=grpTrend, tooltip="Requires ADX to be above this number. Filters out sideways, choppy markets.")

// =========================================================================
// 2. INDICATORS & FILTERS
// =========================================================================
fastEma = ta.ema(close, fastLen)
slowEma = ta.ema(close, slowLen)
macroTrend = ta.ema(close, trendLen)
atr = ta.atr(atrLen)

// ADX Calculation for Chop Filter
[diPlus, diMinus, adx] = ta.dmi(14, 14)
isTrending = adx > adxThresh

// Session Filter Logic
inSession = useTime ? not na(time(timeframe.period, tradeTime)) : true

// Plotting
plot(fastEma, color=color.new(color.blue, 0), title="9 EMA", linewidth=1)
plot(slowEma, color=color.new(color.orange, 0), title="21 EMA", linewidth=1)
plot(macroTrend, color=color.new(color.white, 0), title="200 EMA", linewidth=2)

// =========================================================================
// 3. EXECUTION LOGIC & POSITION SIZING
// =========================================================================
longSignal = ta.crossover(fastEma, slowEma) and close > macroTrend and isTrending and inSession
shortSignal = ta.crossunder(fastEma, slowEma) and close < macroTrend and isTrending and inSession

// Persistent variables for dynamic trade management
var float entryPrice = na
var float slPrice = na
var float tp1Price = na
var float tp2Price = na
var bool  tp1Hit = false

// Position Sizing Math (Risk % / Stop Loss Distance)
riskAmount = (strategy.equity * riskPct) / 100
slDistance = atr * slMult
tradeQty = slDistance > 0 ? (riskAmount / slDistance) : 0

if (longSignal and strategy.position_size == 0)
    entryPrice := close
    slPrice := close - slDistance
    tp1Price := close + (atr * tp1Mult)
    tp2Price := close + (atr * tp2Mult)
    tp1Hit := false
    strategy.entry("Long", strategy.long, qty=tradeQty)

if (shortSignal and strategy.position_size == 0)
    entryPrice := close
    slPrice := close + slDistance
    tp1Price := close - (atr * tp1Mult)
    tp2Price := close - (atr * tp2Mult)
    tp1Hit := false
    strategy.entry("Short", strategy.short, qty=tradeQty)

// =========================================================================
// 4. ADVANCED TRADE MANAGEMENT (Scale-outs & Breakeven)
// =========================================================================
if (strategy.position_size > 0)
    // Check if TP1 is hit to trigger breakeven
    if high >= tp1Price
        tp1Hit := true
    // If TP1 is hit, SL moves to Entry. Otherwise, it stays at original SL.
    activeSL = tp1Hit ? entryPrice : slPrice
    
    // Manage Exits
    strategy.exit("TP1", "Long", qty_percent=50, limit=tp1Price, stop=activeSL)
    strategy.exit("TP2", "Long", limit=tp2Price, stop=activeSL)

if (strategy.position_size < 0)
    if low <= tp1Price
        tp1Hit := true
    activeSL = tp1Hit ? entryPrice : slPrice
    
    strategy.exit("TP1", "Short", qty_percent=50, limit=tp1Price, stop=activeSL)
    strategy.exit("TP2", "Short", limit=tp2Price, stop=activeSL)

// =========================================================================
// 5. VISUAL SIGNALS & HUD DASHBOARD
// =========================================================================
plotshape(series=longSignal and strategy.position_size == 0, title="Long Entry", location=location.belowbar, color=color.green, style=shape.labelup, text="BUY", textcolor=color.white, size=size.small)
plotshape(series=shortSignal and strategy.position_size == 0, title="Short Entry", location=location.abovebar, color=color.red, style=shape.labeldown, text="SELL", textcolor=color.white, size=size.small)

// HUD (Heads Up Display)
var table hud = table.new(position.bottom_right, 2, 4, border_width=1)
if barstate.islast
    table.cell(hud, 0, 0, "Macro Trend (200 EMA)", text_color=color.white, bgcolor=color.gray)
    table.cell(hud, 1, 0, close > macroTrend ? "BULLISH" : "BEARISH", text_color=color.white, bgcolor=close > macroTrend ? color.green : color.red)
    
    table.cell(hud, 0, 1, "Market State (ADX)", text_color=color.white, bgcolor=color.gray)
    table.cell(hud, 1, 1, isTrending ? "TRENDING" : "CHOPPING", text_color=color.white, bgcolor=isTrending ? color.green : color.orange)
    
    table.cell(hud, 0, 2, "Session Active", text_color=color.white, bgcolor=color.gray)
    table.cell(hud, 1, 2, inSession ? "YES" : "NO", text_color=color.white, bgcolor=inSession ? color.green : color.red)
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

Pro-Tips for using this script:

The HUD Dashboard: Look at the bottom right of your chart. If the ADX cell says "CHOPPING" (orange), the script will intentionally ignore 9/21 crosses to save you from getting stopped out in a flat market.

Asset specific tuning: Because this uses ATR (volatility) for targets, it adapts automatically whether you are trading Forex (like EUR/USD), Indices (like NAS100), or Crypto.

Trading Hours: By default, it trades between 09:30 and 15:30. You must ensure your TradingView chart is set to the Exchange Timezone (bottom right corner of TradingView) so the hours align correctly with market open/close.

Breakeven Mechanic: You will notice on the chart that once a trade hits its first target, the strategy often exits the second half of the trade precisely at your entry price. This is the "free ride" mechanic in action—the hallmark of professional risk management.
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

Translating this strategy from Pine Script (which manages virtual positions with simple functions like qty_percent) to MetaTrader's C++ based languages (MQL4/MQL5) requires an architectural shift.

MetaTrader does not have a native "close 50% of the trade at this target" command for pending orders. The professional standard to achieve this is the "Split-Position Setup": when a signal fires, the Expert Advisor (EA) opens two separate positions at half the risk. One has a Take Profit at TP1, the other has a Take Profit at TP2. A trailing loop runs in the background; when price hits TP1 distance, it moves the Stop Loss of the remaining trade to breakeven.

Here is the complete, compiled-ready code for both platforms. Note that the visual HUD has been omitted to ensure the execution engine remains lightning-fast without cluttering the MetaTrader chart objects.
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

1. MetaTrader 4 (MQL4) Expert Advisor

Save this file as Pro_5Min_Scalper.mq4 in your MQL4\Experts folder.

Code: Select all

//+------------------------------------------------------------------+
//|                                           Pro_5Min_Scalper.mq4   |
//+------------------------------------------------------------------+
#property copyright "Pro Scalper"
#property link      ""
#property version   "1.00"
#property strict

//--- Inputs
input double   RiskPercent    = 1.0;   // Risk Per Trade (%)
input int      ATR_Period     = 14;    // ATR Period
input double   SL_Multiplier  = 1.5;   // Stop Loss ATR Multiplier
input double   TP1_Multiplier = 1.5;   // TP1 ATR Multiplier (Scale Out)
input double   TP2_Multiplier = 3.0;   // TP2 ATR Multiplier (Runner)

input int      FastEMA        = 9;     // Fast EMA
input int      SlowEMA        = 21;    // Slow EMA
input int      TrendEMA       = 200;   // Macro Trend 200 EMA
input int      ADX_Period     = 14;    // ADX Period
input double   ADX_Threshold  = 20.0;  // ADX Chop Filter Minimum

input bool     UseTimeFilter  = true;
input int      StartHour      = 9;
input int      StartMinute    = 30;
input int      EndHour        = 15;
input int      EndMinute      = 30;

input int      MagicNumber    = 55555; // Unique EA ID

//--- Global
datetime lastBarTime = 0;

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    // 1. Manage Breakeven on every tick
    ManageBreakeven();

    // 2. Only check for new entries on the close of a bar
    if(Time[0] == lastBarTime) return;

    // 3. Check Time Filter
    if(UseTimeFilter && !IsTradingTime()) return;

    // 4. Indicator Calculations (Shift 1 = closed bar, Shift 2 = previous closed bar)
    double fast1 = iMA(_Symbol, 0, FastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
    double fast2 = iMA(_Symbol, 0, FastEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
    
    double slow1 = iMA(_Symbol, 0, SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
    double slow2 = iMA(_Symbol, 0, SlowEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
    
    double trend = iMA(_Symbol, 0, TrendEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
    double adx   = iADX(_Symbol, 0, ADX_Period, PRICE_CLOSE, MODE_MAIN, 1);
    double atr   = iATR(_Symbol, 0, ATR_Period, 1);

    // 5. Entry Logic
    bool buySignal  = (fast1 > slow1 && fast2 <= slow2) && (Close[1] > trend) && (adx > ADX_Threshold);
    bool sellSignal = (fast1 < slow1 && fast2 >= slow2) && (Close[1] < trend) && (adx > ADX_Threshold);

    if(buySignal && OrdersTotal() == 0) ExecuteTrade(OP_BUY, atr);
    if(sellSignal && OrdersTotal() == 0) ExecuteTrade(OP_SELL, atr);

    lastBarTime = Time[0];
}

//+------------------------------------------------------------------+
//| Execute Trade (Splits risk into two positions)                   |
//+------------------------------------------------------------------+
void ExecuteTrade(int type, double atr)
{
    RefreshRates();
    double entryPrice = (type == OP_BUY) ? Ask : Bid;
    
    double slDist = atr * SL_Multiplier;
    double tp1Dist = atr * TP1_Multiplier;
    double tp2Dist = atr * TP2_Multiplier;

    double sl = (type == OP_BUY) ? entryPrice - slDist : entryPrice + slDist;
    double tp1 = (type == OP_BUY) ? entryPrice + tp1Dist : entryPrice - tp1Dist;
    double tp2 = (type == OP_BUY) ? entryPrice + tp2Dist : entryPrice - tp2Dist;

    // Normalize prices for broker digits
    sl = NormalizeDouble(sl, _Digits);
    tp1 = NormalizeDouble(tp1, _Digits);
    tp2 = NormalizeDouble(tp2, _Digits);

    // Calculate Lot Size (Split in half for two positions)
    double totalLots = CalculateLots(slDist);
    double halfLots = NormalizeDouble(totalLots / 2.0, 2);
    double minLot = MarketInfo(_Symbol, MODE_MINLOT);
    if(halfLots < minLot) halfLots = minLot;

    // Send Split Orders
    int ticket1 = OrderSend(_Symbol, type, halfLots, entryPrice, 3, sl, tp1, "ProScalp TP1", MagicNumber, 0, Blue);
    int ticket2 = OrderSend(_Symbol, type, halfLots, entryPrice, 3, sl, tp2, "ProScalp TP2", MagicNumber, 0, Blue);
}

//+------------------------------------------------------------------+
//| Breakeven Management                                             |
//+------------------------------------------------------------------+
void ManageBreakeven()
{
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber)
            {
                double atr = iATR(_Symbol, 0, ATR_Period, 1);
                double tp1Dist = atr * TP1_Multiplier;
                
                if(OrderType() == OP_BUY)
                {
                    // If price reached TP1 equivalent, and SL is still below Entry
                    if(Bid >= OrderOpenPrice() + tp1Dist && OrderStopLoss() < OrderOpenPrice())
                        OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, Green);
                }
                else if(OrderType() == OP_SELL)
                {
                    // If price reached TP1 equivalent, and SL is still above Entry
                    if(Ask <= OrderOpenPrice() - tp1Dist && (OrderStopLoss() > OrderOpenPrice() || OrderStopLoss() == 0))
                        OrderModify(OrderTicket(), OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), 0, Green);
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Utilities                                                        |
//+------------------------------------------------------------------+
bool IsTradingTime()
{
    int currentHour = TimeHour(TimeCurrent());
    int currentMin = TimeMinute(TimeCurrent());
    int currentMins = currentHour * 60 + currentMin;
    int startMins = StartHour * 60 + StartMinute;
    int endMins = EndHour * 60 + EndMinute;
    
    return (currentMins >= startMins && currentMins <= endMins);
}

double CalculateLots(double slDistance)
{
    double riskAmount = AccountFreeMargin() * (RiskPercent / 100.0);
    double tickValue = MarketInfo(_Symbol, MODE_TICKVALUE);
    double tickSize = MarketInfo(_Symbol, MODE_TICKSIZE);
    
    double slTicks = slDistance / tickSize;
    if(slTicks <= 0 || tickValue <= 0) return MarketInfo(_Symbol, MODE_MINLOT);
    
    double lots = riskAmount / (slTicks * tickValue);
    return lots;
}
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

2. MetaTrader 5 (MQL5) Expert Advisor

Save this file as Pro_5Min_Scalper.mq5 in your MQL5\Experts folder. Note that MQL5 requires indicator handles setup in OnInit(). This requires a hedging account (the default for 99% of modern MT5 brokers) so you can hold two separate positions for TP1 and TP2.

Code: Select all

//+------------------------------------------------------------------+
//|                                           Pro_5Min_Scalper.mq5   |
//+------------------------------------------------------------------+
#property copyright "Pro Scalper"
#property version   "1.00"
#include <Trade\Trade.mqh>

//--- Inputs
input double   RiskPercent    = 1.0;   // Risk Per Trade (%)
input int      ATR_Period     = 14;    // ATR Period
input double   SL_Multiplier  = 1.5;   // Stop Loss ATR Multiplier
input double   TP1_Multiplier = 1.5;   // TP1 ATR Multiplier (Scale Out)
input double   TP2_Multiplier = 3.0;   // TP2 ATR Multiplier (Runner)

input int      FastEMA        = 9;     // Fast EMA
input int      SlowEMA        = 21;    // Slow EMA
input int      TrendEMA       = 200;   // Macro Trend 200 EMA
input int      ADX_Period     = 14;    // ADX Period
input double   ADX_Threshold  = 20.0;  // ADX Chop Filter Minimum

input bool     UseTimeFilter  = true;
input int      StartHour      = 9;
input int      StartMinute    = 30;
input int      EndHour        = 15;
input int      EndMinute      = 30;
input ulong    MagicNumber    = 55555; // Unique EA ID

//--- Globals
CTrade         trade;
datetime       lastBarTime;
int            hFast, hSlow, hTrend, hADX, hATR;
double         bufFast[], bufSlow[], bufTrend[], bufADX[], bufATR[];

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    trade.SetExpertMagicNumber(MagicNumber);
    
    hFast  = iMA(_Symbol, PERIOD_CURRENT, FastEMA, 0, MODE_EMA, PRICE_CLOSE);
    hSlow  = iMA(_Symbol, PERIOD_CURRENT, SlowEMA, 0, MODE_EMA, PRICE_CLOSE);
    hTrend = iMA(_Symbol, PERIOD_CURRENT, TrendEMA, 0, MODE_EMA, PRICE_CLOSE);
    hADX   = iADX(_Symbol, PERIOD_CURRENT, ADX_Period);
    hATR   = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);
    
    ArraySetAsSeries(bufFast, true);
    ArraySetAsSeries(bufSlow, true);
    ArraySetAsSeries(bufTrend, true);
    ArraySetAsSeries(bufADX, true);
    ArraySetAsSeries(bufATR, true);
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    ManageBreakeven();

    datetime currentTime = iTime(_Symbol, PERIOD_CURRENT, 0);
    if(currentTime == lastBarTime) return; // Wait for bar close

    if(UseTimeFilter && !IsTradingTime()) return;
    if(PositionsTotal() > 0) return; // Prevent multiple entries

    // Update indicator buffers (index 1 is previous closed bar, index 2 is the one before)
    if(CopyBuffer(hFast, 0, 1, 2, bufFast) <= 0) return;
    if(CopyBuffer(hSlow, 0, 1, 2, bufSlow) <= 0) return;
    if(CopyBuffer(hTrend, 0, 1, 1, bufTrend) <= 0) return;
    if(CopyBuffer(hADX, 0, 1, 1, bufADX) <= 0) return;
    if(CopyBuffer(hATR, 0, 1, 1, bufATR) <= 0) return;

    bool buySignal = (bufFast[0] > bufSlow[0] && bufFast[1] <= bufSlow[1]) && 
                     (iClose(_Symbol, PERIOD_CURRENT, 1) > bufTrend[0]) && 
                     (bufADX[0] > ADX_Threshold);
                     
    bool sellSignal = (bufFast[0] < bufSlow[0] && bufFast[1] >= bufSlow[1]) && 
                      (iClose(_Symbol, PERIOD_CURRENT, 1) < bufTrend[0]) && 
                      (bufADX[0] > ADX_Threshold);

    if(buySignal) ExecuteTrade(ORDER_TYPE_BUY, bufATR[0]);
    if(sellSignal) ExecuteTrade(ORDER_TYPE_SELL, bufATR[0]);

    lastBarTime = currentTime;
}

//+------------------------------------------------------------------+
//| Execute Split Trades                                             |
//+------------------------------------------------------------------+
void ExecuteTrade(ENUM_ORDER_TYPE type, double atr)
{
    double entryPrice = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
    
    double slDist = atr * SL_Multiplier;
    double tp1Dist = atr * TP1_Multiplier;
    double tp2Dist = atr * TP2_Multiplier;

    double sl = (type == ORDER_TYPE_BUY) ? entryPrice - slDist : entryPrice + slDist;
    double tp1 = (type == ORDER_TYPE_BUY) ? entryPrice + tp1Dist : entryPrice - tp1Dist;
    double tp2 = (type == ORDER_TYPE_BUY) ? entryPrice + tp2Dist : entryPrice - tp2Dist;

    sl = NormalizeDouble(sl, _Digits);
    tp1 = NormalizeDouble(tp1, _Digits);
    tp2 = NormalizeDouble(tp2, _Digits);

    double totalLots = CalculateLots(slDist);
    double halfLots = NormalizeDouble(totalLots / 2.0, 2);
    double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    if(halfLots < minLot) halfLots = minLot;

    // Execute Position 1 (TP1)
    trade.PositionOpen(_Symbol, type, halfLots, entryPrice, sl, tp1, "ProScalp TP1");
    // Execute Position 2 (TP2)
    trade.PositionOpen(_Symbol, type, halfLots, entryPrice, sl, tp2, "ProScalp TP2");
}

//+------------------------------------------------------------------+
//| Manage Breakeven (Trailing Logic)                                |
//+------------------------------------------------------------------+
void ManageBreakeven()
{
    if(CopyBuffer(hATR, 0, 1, 1, bufATR) <= 0) return;
    double tp1Dist = bufATR[0] * TP1_Multiplier;

    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        ulong ticket = PositionGetTicket(i);
        if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
        {
            double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            double currentSL = PositionGetDouble(POSITION_SL);
            long type = PositionGetInteger(POSITION_TYPE);
            
            if(type == POSITION_TYPE_BUY)
            {
                double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
                if(currentBid >= openPrice + tp1Dist && currentSL < openPrice)
                    trade.PositionModify(ticket, openPrice, PositionGetDouble(POSITION_TP));
            }
            else if(type == POSITION_TYPE_SELL)
            {
                double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
                if(currentAsk <= openPrice - tp1Dist && (currentSL > openPrice || currentSL == 0))
                    trade.PositionModify(ticket, openPrice, PositionGetDouble(POSITION_TP));
            }
        }
    }
}

//+------------------------------------------------------------------+
//| Utilities                                                        |
//+------------------------------------------------------------------+
bool IsTradingTime()
{
    MqlDateTime dt;
    TimeToStruct(TimeCurrent(), dt);
    int currentMins = dt.hour * 60 + dt.min;
    int startMins = StartHour * 60 + StartMinute;
    int endMins = EndHour * 60 + EndMinute;
    
    return (currentMins >= startMins && currentMins <= endMins);
}

double CalculateLots(double slDistance)
{
    double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * (RiskPercent / 100.0);
    double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
    double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
    
    double slTicks = slDistance / tickSize;
    if(slTicks <= 0 || tickValue <= 0) return SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    
    double lots = riskAmount / (slTicks * tickValue);
    return NormalizeDouble(lots, 2);
}
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

Installation & Deployment

1.) Open your MetaTrader platform and press F4 to open the MetaEditor.

2.) In the Navigator on the left, right-click Experts > New File.

3.) Name it Pro_5Min_Scalper, delete everything in the default template, and paste the corresponding code above.

4.) Click Compile (F7). Check the logs at the bottom to ensure there are 0 errors.

5.) Attach it to a 5-Minute Chart. Ensure "Allow Live Trading" / "Allow Algo Trading" is checked in the EA properties.

Note: MT4/MT5 brokers run on their own server time (usually EET). You must adjust the StartHour and EndHour inputs to match your broker's time, not your local computer time.
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

ranslating this strategy to cTrader (using C# / cAlgo.API) is a fantastic upgrade. cTrader's native architecture handles partial execution, pip math, and position sizing much more elegantly than MetaTrader.

Because cTrader uses Labels instead of Magic Numbers, and processes Stop Loss and Take Profit in Pips rather than absolute price during order execution, the code becomes highly readable. We will maintain the Split-Position architecture (opening two trades with half-volume each) as it ensures the broker server hard-stops both your TP1 and TP2 targets even if your computer disconnects.

The cTrader cBot (C#)
Here is the complete, ready-to-compile cBot code 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 Pro5MinScalper : Robot
    {
        // =========================================================================
        // 1. INPUTS: Pro Trade Desk Settings
        // =========================================================================
        [Parameter("Risk Per Trade (%)", DefaultValue = 1.0, Group = "1. Risk Management")]
        public double RiskPercent { get; set; }

        [Parameter("ATR Period", DefaultValue = 14, Group = "1. Risk Management")]
        public int AtrPeriod { get; set; }

        [Parameter("Stop Loss (ATR Multiplier)", DefaultValue = 1.5, Group = "1. Risk Management")]
        public double SlMultiplier { get; set; }

        [Parameter("TP1 Scale Out (ATR Multiplier)", DefaultValue = 1.5, Group = "1. Risk Management")]
        public double Tp1Multiplier { get; set; }

        [Parameter("TP2 Runner (ATR Multiplier)", DefaultValue = 3.0, Group = "1. Risk Management")]
        public double Tp2Multiplier { get; set; }

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

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

        [Parameter("Macro Trend (200 EMA)", DefaultValue = 200, Group = "2. Trend Filters")]
        public int TrendEmaPeriod { get; set; }

        [Parameter("ADX Period", DefaultValue = 14, Group = "2. Trend Filters")]
        public int AdxPeriod { get; set; }

        [Parameter("ADX Minimum (Chop Filter)", DefaultValue = 20.0, Group = "2. Trend Filters")]
        public double AdxThreshold { get; set; }

        [Parameter("Enable Time Filter", DefaultValue = true, Group = "3. Session Times")]
        public bool UseTimeFilter { get; set; }

        [Parameter("Start Hour (Server Time)", DefaultValue = 9, Group = "3. Session Times")]
        public int StartHour { get; set; }

        [Parameter("End Hour (Server Time)", DefaultValue = 15, Group = "3. Session Times")]
        public int EndHour { get; set; }

        private ExponentialMovingAverage _fastEma;
        private ExponentialMovingAverage _slowEma;
        private ExponentialMovingAverage _trendEma;
        private DirectionalMovementSystem _adx;
        private AverageTrueRange _atr;

        private const string BotLabel = "ProScalper_5Min";

        // =========================================================================
        // 2. INITIALIZATION
        // =========================================================================
        protected override void OnStart()
        {
            // Initialize indicators using standard cAlgo library
            _fastEma = Indicators.ExponentialMovingAverage(Bars.ClosePrices, FastEmaPeriod);
            _slowEma = Indicators.ExponentialMovingAverage(Bars.ClosePrices, SlowEmaPeriod);
            _trendEma = Indicators.ExponentialMovingAverage(Bars.ClosePrices, TrendEmaPeriod);
            _adx = Indicators.DirectionalMovementSystem(AdxPeriod);
            _atr = Indicators.AverageTrueRange(AtrPeriod, MovingAverageType.Simple);
        }

        // =========================================================================
        // 3. BREAKEVEN MANAGEMENT (Runs every tick)
        // =========================================================================
        protected override void OnTick()
        {
            var openPositions = Positions.FindAll(BotLabel, SymbolName);
            if (openPositions.Length == 0) return;

            double currentAtr = _atr.Result.Last(1);
            double tp1Distance = currentAtr * Tp1Multiplier;

            foreach (var pos in openPositions)
            {
                if (pos.TradeType == TradeType.Buy)
                {
                    // If price reached TP1 equivalent, and SL is still below Entry
                    if (Symbol.Bid >= pos.EntryPrice + tp1Distance && pos.StopLoss < pos.EntryPrice)
                    {
                        ModifyPosition(pos, pos.EntryPrice, pos.TakeProfit);
                        Print("Long position SL moved to Breakeven.");
                    }
                }
                else if (pos.TradeType == TradeType.Sell)
                {
                    // If price reached TP1 equivalent, and SL is still above Entry
                    if (Symbol.Ask <= pos.EntryPrice - tp1Distance && (pos.StopLoss > pos.EntryPrice || pos.StopLoss == null))
                    {
                        ModifyPosition(pos, pos.EntryPrice, pos.TakeProfit);
                        Print("Short position SL moved to Breakeven.");
                    }
                }
            }
        }

        // =========================================================================
        // 4. ENTRY LOGIC (Runs on bar close)
        // =========================================================================
        protected override void OnBar()
        {
            // Only take trades if no positions are currently open
            if (Positions.FindAll(BotLabel, SymbolName).Length > 0) return;

            if (UseTimeFilter && !IsTradingTime()) return;

            // Indicator values for the last closed bar (index 1) and the previous (index 2)
            int closedBar = Bars.Count - 2;
            int prevBar = Bars.Count - 3;

            bool buySignal = _fastEma.Result[closedBar] > _slowEma.Result[closedBar] &&
                             _fastEma.Result[prevBar] <= _slowEma.Result[prevBar] &&
                             Bars.ClosePrices[closedBar] > _trendEma.Result[closedBar] &&
                             _adx.ADX[closedBar] > AdxThreshold;

            bool sellSignal = _fastEma.Result[closedBar] < _slowEma.Result[closedBar] &&
                              _fastEma.Result[prevBar] >= _slowEma.Result[prevBar] &&
                              Bars.ClosePrices[closedBar] < _trendEma.Result[closedBar] &&
                              _adx.ADX[closedBar] > AdxThreshold;

            if (buySignal) ExecuteSplitTrade(TradeType.Buy);
            if (sellSignal) ExecuteSplitTrade(TradeType.Sell);
        }

        // =========================================================================
        // 5. TRADE EXECUTION & MATH
        // =========================================================================
        private void ExecuteSplitTrade(TradeType direction)
        {
            double atr = _atr.Result.Last(1);
            
            // Calculate distances in absolute price, then convert to Pips for cTrader API
            double slDistPrice = atr * SlMultiplier;
            double tp1DistPrice = atr * Tp1Multiplier;
            double tp2DistPrice = atr * Tp2Multiplier;

            double slPips = slDistPrice / Symbol.PipSize;
            double tp1Pips = tp1DistPrice / Symbol.PipSize;
            double tp2Pips = tp2DistPrice / Symbol.PipSize;

            // Position Sizing based on Risk %
            double totalVolume = CalculateVolume(slPips);
            double halfVolume = Symbol.NormalizeVolumeInUnits(totalVolume / 2.0, RoundingMode.Down);
            
            // Enforce broker minimums
            if (halfVolume < Symbol.VolumeInUnitsMin) 
                halfVolume = Symbol.VolumeInUnitsMin;

            // Execute Position 1 (Take Profit 1)
            ExecuteMarketOrder(direction, SymbolName, halfVolume, BotLabel, slPips, tp1Pips);
            
            // Execute Position 2 (Take Profit 2 - The Runner)
            ExecuteMarketOrder(direction, SymbolName, halfVolume, BotLabel, slPips, tp2Pips);
        }

        private double CalculateVolume(double stopLossPips)
        {
            double riskAmount = Account.Equity * (RiskPercent / 100.0);
            // Symbol.PipValue is the value of 1 pip for 1 unit of volume in cTrader
            double exactVolume = riskAmount / (stopLossPips * Symbol.PipValue);
            return exactVolume;
        }

        private bool IsTradingTime()
        {
            DateTime time = Server.Time;
            int currentMins = time.Hour * 60 + time.Minute;
            int startMins = StartHour * 60 + StartMinute;
            int endMins = EndHour * 60 + EndMinute;

            return (currentMins >= startMins && currentMins <= endMins);
        }
    }
}
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 5-Minute Chart: The Scalper's Middle Ground

Post by PTScalper »

How to Install it in cTrader:

1.) Open cTrader and click on the Automate tab on the left sidebar (the robot icon).

2.) Click New cBot at the top right of the bots list. Name it Pro_5Min_Scalper.

3.) The code editor will open. Delete everything inside, and paste the code provided above.

4.) Click the Build button (the hammer icon or Ctrl+B) at the top of the editor. Ensure you see "Build Succeeded" in the output window.

5.) Go to your 5-Minute chart, click the cBots dropdown at the top of the chart, and add Pro_5Min_Scalper to the chart.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply