Advertisement IC Markets

The Market Doesn’t Care About Your Feelings

Master exponential money management, position sizing calculators, strict daily stop-loss limits, and overcoming FOMO on micro-timeframes.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Market Doesn’t Care About Your Feelings

Post by PTScalper »

2. MetaTrader 4 (MQL4) Expert Advisor

MQL4 does not utilize the standard CTrade library, relying instead on raw OrderSend() functions and required price normalizations. Save this as an .mq4 file.

Code: Select all

//+------------------------------------------------------------------+
//|                                              D1M15_Sweep_MT4.mq4 |
//+------------------------------------------------------------------+
#property strict

input double RiskPercent = 1.0;      // Risk Per Trade (%)
input double RiskRewardRatio = 2.0;  // Risk/Reward Ratio
input int    MagicNumber = 123456;   // EA Magic Number

void OnTick()
{
    static datetime lastTime = 0;
    datetime currentTime = iTime(Symbol(), PERIOD_M15, 0);
    if(currentTime == lastTime || currentTime == 0) return;
    
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
                return; 
        }
    }
    
    lastTime = currentTime;

    double pdh = iHigh(Symbol(), PERIOD_D1, 1);
    double pdl = iLow(Symbol(), PERIOD_D1, 1);
    
    if(pdh == 0 || pdl == 0) return;

    double m15Open  = iOpen(Symbol(), PERIOD_M15, 1);
    double m15High  = iHigh(Symbol(), PERIOD_M15, 1);
    double m15Low   = iLow(Symbol(), PERIOD_M15, 1);
    double m15Close = iClose(Symbol(), PERIOD_M15, 1);

    bool bearishSweep = (m15High > pdh) && (m15Close < pdh) && (m15Open < pdh);
    bool bullishSweep = (m15Low < pdl)  && (m15Close > pdl) && (m15Open > pdl);

    if(bearishSweep)
    {
        double hardStop = m15High;
        double entryPrice = Bid;
        
        double riskAmount = AccountEquity() * (RiskPercent / 100.0);
        double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
        double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
        
        double stopLossTicks = (hardStop - entryPrice) / tickSize;
        if(stopLossTicks <= 0) return;
        
        double rawLots = riskAmount / (stopLossTicks * tickValue);
        
        double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
        double minLot = MarketInfo(Symbol(), MODE_MINLOT);
        double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
        
        double lots = MathFloor(rawLots / lotStep) * lotStep;
        if(lots > maxLot) lots = maxLot;
        
        if(lots >= minLot)
        {
            double tp = entryPrice - ((hardStop - entryPrice) * RiskRewardRatio);
            
            // MT4 requires StopLoss and TakeProfit to be strictly normalized to chart digits
            hardStop = NormalizeDouble(hardStop, Digits);
            tp = NormalizeDouble(tp, Digits);
            
            int ticket = OrderSend(Symbol(), OP_SELL, lots, entryPrice, 3, hardStop, tp, "Sweep Short", MagicNumber, 0, clrRed);
        }
    }
    else if(bullishSweep)
    {
        double hardStop = m15Low;
        double entryPrice = Ask;
        
        double riskAmount = AccountEquity() * (RiskPercent / 100.0);
        double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
        double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
        
        double stopLossTicks = (entryPrice - hardStop) / tickSize;
        if(stopLossTicks <= 0) return;
        
        double rawLots = riskAmount / (stopLossTicks * tickValue);
        
        double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
        double minLot = MarketInfo(Symbol(), MODE_MINLOT);
        double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
        
        double lots = MathFloor(rawLots / lotStep) * lotStep;
        if(lots > maxLot) lots = maxLot;
        
        if(lots >= minLot)
        {
            double tp = entryPrice + ((entryPrice - hardStop) * RiskRewardRatio);
            
            hardStop = NormalizeDouble(hardStop, Digits);
            tp = NormalizeDouble(tp, Digits);
            
            int ticket = OrderSend(Symbol(), OP_BUY, lots, entryPrice, 3, hardStop, tp, "Sweep Long", MagicNumber, 0, clrBlue);
        }
    }
}
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 Market Doesn’t Care About Your Feelings

Post by PTScalper »

To elevate a script from a working concept to a production-ready trading algorithm, the architecture must account for market microstructure—specifically spread widening, broker execution limits, and slippage.

A professional implementation uses Object-Oriented principles, isolates execution logic from signal generation, and protects the account from broker-side rejections (like ERR_INVALID_STOPS or A-Book ECN rejections).

Here is the enterprise-grade MetaTrader 5 (MQL5) implementation, followed by the specific execution handling required for MetaTrader 4 (MQL4) ECN brokers.
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 Market Doesn’t Care About Your Feelings

Post by PTScalper »

1. Production-Ready MT5 (MQL5) Architecture

This version introduces a CSymbolInfo wrapper for precise tick tracking, a hard spread filter to avoid executing during news/rollover liquidity vacuums, and StopLevel normalization to prevent broker rejections on tight wicks.

Code: Select all

//+------------------------------------------------------------------+
//|                                      Pro_D1M15_Sweep_MT5.mq5     |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>

input group "Risk Management"
input double   InpRiskPercent    = 1.0;      // Risk Per Trade (%)
input double   InpRiskReward     = 2.0;      // Risk/Reward Ratio
input double   InpMaxRiskLots    = 10.0;     // Hard Lot Size Cap

input group "Market Microstructure"
input int      InpMaxSpreadPts   = 30;       // Max Allowed Spread (Points)
input ulong    InpMaxSlippagePts = 5;        // Max Slippage (Points)

input group "System Parameters"
input ulong    InpMagicNumber    = 888888;   // Magic Number
input string   InpTradeComment   = "M15_Sweep";

CTrade         m_trade;
CSymbolInfo    m_symbol;
CPositionInfo  m_position;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    if(!m_symbol.Name(_Symbol)) return(INIT_FAILED);
    
    m_trade.SetExpertMagicNumber(InpMagicNumber);
    m_trade.SetDeviationInPoints(InpMaxSlippagePts);
    m_trade.SetTypeFilling(ORDER_FILLING_FOK); // Fill Or Kill for exact execution
    
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    if(!IsNewBar(PERIOD_M15)) return;
    if(IsPositionOpen()) return;
    
    m_symbol.RefreshRates();
    
    // Spread Filter: Abort if liquidity is absent and spread is blown out
    if(m_symbol.Spread() > InpMaxSpreadPts)
    {
        PrintFormat("Signal aborted: Spread %d exceeds max %d points.", m_symbol.Spread(), InpMaxSpreadPts);
        return;
    }

    double pdh = iHigh(_Symbol, PERIOD_D1, 1);
    double pdl = iLow(_Symbol, PERIOD_D1, 1);
    
    if(pdh == 0 || pdl == 0) return;

    double m15Open  = iOpen(_Symbol, PERIOD_M15, 1);
    double m15High  = iHigh(_Symbol, PERIOD_M15, 1);
    double m15Low   = iLow(_Symbol, PERIOD_M15, 1);
    double m15Close = iClose(_Symbol, PERIOD_M15, 1);

    bool bearishSweep = (m15High > pdh) && (m15Close < pdh) && (m15Open < pdh);
    bool bullishSweep = (m15Low < pdl)  && (m15Close > pdl) && (m15Open > pdl);

    if(bearishSweep) ExecuteTrade(ORDER_TYPE_SELL, m15High);
    if(bullishSweep) ExecuteTrade(ORDER_TYPE_BUY, m15Low);
}

//+------------------------------------------------------------------+
//| Secure Execution & Sizing Module                                 |
//+------------------------------------------------------------------+
void ExecuteTrade(ENUM_ORDER_TYPE type, double hardStop)
{
    double entryPrice = (type == ORDER_TYPE_BUY) ? m_symbol.Ask() : m_symbol.Bid();
    
    // StopLevel check: Brokers reject stops placed inside the spread/stoplevel zone
    double minStopDist = m_symbol.StopsLevel() * m_symbol.Point();
    if(MathAbs(entryPrice - hardStop) < minStopDist)
    {
        hardStop = (type == ORDER_TYPE_BUY) ? entryPrice - minStopDist : entryPrice + minStopDist;
        Print("Stop adjusted to broker minimum StopLevel.");
    }

    double riskAmount = AccountInfoDouble(ACCOUNT_EQUITY) * (InpRiskPercent / 100.0);
    double stopLossTicks = MathAbs(entryPrice - hardStop) / m_symbol.TickSize();
    
    if(stopLossTicks <= 0) return;
    
    double rawLots = riskAmount / (stopLossTicks * m_symbol.TickValue());
    double lots = NormalizeLots(rawLots);
    
    if(lots == 0) return;

    double tpDist = MathAbs(entryPrice - hardStop) * InpRiskReward;
    double tpPrice = (type == ORDER_TYPE_BUY) ? entryPrice + tpDist : entryPrice - tpDist;

    if(type == ORDER_TYPE_BUY)
        m_trade.Buy(lots, _Symbol, entryPrice, hardStop, tpPrice, InpTradeComment);
    else
        m_trade.Sell(lots, _Symbol, entryPrice, hardStop, tpPrice, InpTradeComment);
        
    if(m_trade.ResultRetcode() != TRADE_RETCODE_DONE)
        PrintFormat("Execution failed: %s", m_trade.ResultRetcodeDescription());
}

//+------------------------------------------------------------------+
//| Volume Normalization                                             |
//+------------------------------------------------------------------+
double NormalizeLots(double calculatedLots)
{
    double minLot = m_symbol.LotsMin();
    double maxLot = MathMin(m_symbol.LotsMax(), InpMaxRiskLots);
    double lotStep = m_symbol.LotsStep();
    
    double lots = MathFloor(calculatedLots / lotStep) * lotStep;
    
    if(lots < minLot)
    {
        Print("Calculated risk falls below broker minimum lot size. Trade aborted.");
        return 0;
    }
    if(lots > maxLot)
    {
        PrintFormat("Lot size capped at %.2f to prevent overexposure.", maxLot);
        return maxLot;
    }
    
    return lots;
}

//+------------------------------------------------------------------+
//| State Tracking                                                   |
//+------------------------------------------------------------------+
bool IsNewBar(ENUM_TIMEFRAMES timeframe)
{
    static datetime lastBarTime = 0;
    datetime currentBarTime = (datetime)SeriesInfoInteger(_Symbol, timeframe, SERIES_LASTBAR_DATE);
    
    if(currentBarTime != lastBarTime)
    {
        lastBarTime = currentBarTime;
        return true;
    }
    return false;
}

bool IsPositionOpen()
{
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(m_position.SelectByIndex(i))
            if(m_position.Symbol() == _Symbol && m_position.Magic() == InpMagicNumber)
                return true;
    }
    return false;
}
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 Market Doesn’t Care About Your Feelings

Post by PTScalper »

2. Pro MT4 (MQL4): The ECN / STP Wrapper

In MT4, professional execution requires an entirely different approach to OrderSend(). Many STP/ECN (A-Book) brokers will outright reject an OrderSend command that includes a Stop Loss and Take Profit at market execution.

To make the MT4 version professional, the execution logic must place a "naked" order first, verify the ticket, and then rapidly modify the order to attach the predefined risk parameters.

Code: Select all

//+------------------------------------------------------------------+
//| MQL4 ECN Execution Module (Replace inside MT4 EA)                |
//+------------------------------------------------------------------+
void ExecuteTradeECN(int cmd, double lots, double hardStop, double tpPrice)
{
    double entryPrice = (cmd == OP_BUY) ? Ask : Bid;
    
    // Normalize to exact chart digits to prevent ERR_INVALID_PRICE
    entryPrice = NormalizeDouble(entryPrice, Digits);
    hardStop   = NormalizeDouble(hardStop, Digits);
    tpPrice    = NormalizeDouble(tpPrice, Digits);

    // 1. Send the order with NO stops (ECN safe)
    int ticket = OrderSend(Symbol(), cmd, lots, entryPrice, 5, 0, 0, "Sweep", 888888, 0, (cmd == OP_BUY) ? clrBlue : clrRed);
    
    // 2. If successful, immediately modify to attach SL and TP
    if(ticket > 0)
    {
        if(OrderSelect(ticket, SELECT_BY_TICKET))
        {
            bool res = OrderModify(ticket, OrderOpenPrice(), hardStop, tpPrice, 0, clrNONE);
            if(!res)
            {
                Print("Critical Warning: Entry filled but Stop Loss failed to attach! Error: ", GetLastError());
                // In a true pro system, you trigger an emergency market close here if the modification fails.
            }
        }
    }
    else
    {
        Print("Execution failed. Error code: ", GetLastError());
    }
}
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 Market Doesn’t Care About Your Feelings

Post by PTScalper »

Key Professional Upgrades Applied:

Fill-Or-Kill (FOK) Routing: ORDER_FILLING_FOK guarantees that if the broker cannot fill the entire volume requested at the price you want, the order is canceled rather than partially filled at a terrible average price.

Max Spread Caps: Highly liquid pairs normally trade tightly, but spreads widen drastically during news releases or the daily 5:00 PM EST rollover. The spread check keeps you out of liquidity sweeps designed to trigger premature stop losses.

Lot Size Caps (InpMaxRiskLots): Prevents catastrophic errors. If a wick is only 0.5 pips deep, the 1% risk math might attempt to open an absurdly large position (e.g., 200 lots). The cap forces a hard ceiling on exposure.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply