Re: The Scalper’s Paradox: Why We Win the 1-Minute Battles but Lose the War (and our accounts)
Posted: Sat Sep 26, 2026 6:00 pm
1. MetaTrader 4 (MQL4)
Save this file as RiskContainer.mq4 in your MQL4/Experts folder.
Save this file as RiskContainer.mq4 in your MQL4/Experts folder.
Code: Select all
//+------------------------------------------------------------------+
//| RiskContainer.mq4 |
//| "The House Plan & Scalp Bricks" |
//+------------------------------------------------------------------+
#property copyright "Risk Container"
#property link ""
#property version "1.00"
#property strict
//--- 1. THE CONTAINER INPUTS
input string InpSessionHeader = "=== The Container (Risk/Time) ==="; // --- Risk Settings ---
input string InpSessionStart = "09:30"; // Session Start (Server HH:MM)
input string InpSessionEnd = "11:30"; // Session End (Server HH:MM)
input double InpMaxDailyLossPct = 2.0; // Max Daily Loss (%)
input double InpDailyGoalPct = 4.0; // Good Enough Goal (%)
input double InpLotSize = 0.1; // Fixed Lot Size
input int InpMagicNumber = 991122; // EA Magic Number
input int InpSlippage = 3; // Max Slippage (points)
//--- 2. THE BRICKS INPUTS
input string InpBricksHeader = "=== The Bricks (Scalp Logic) ==="; // --- Scalp Settings ---
input int InpFastEMA = 9; // Fast EMA Period
input int InpSlowEMA = 21; // Slow EMA Period
//--- Internal State Variables
datetime g_currentDay;
double g_startOfDayEquity;
bool g_tradingHalted;
datetime g_lastBarTime;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
g_currentDay = TimeDay(TimeCurrent());
g_startOfDayEquity = AccountEquity();
g_tradingHalted = false;
g_lastBarTime = 0;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
ManageDailyRollover();
EnforceContainerLimits();
UpdateDashboard();
// Check bar close to execute the Bricks (avoids intra-bar false signals)
if(Time[0] != g_lastBarTime)
{
g_lastBarTime = Time[0];
ExecuteBricks();
}
}
//+------------------------------------------------------------------+
//| Container: Daily Rollover Reset |
//+------------------------------------------------------------------+
void ManageDailyRollover()
{
if(TimeDay(TimeCurrent()) != g_currentDay)
{
g_currentDay = TimeDay(TimeCurrent());
g_startOfDayEquity = AccountEquity();
g_tradingHalted = false;
Print("[Container] New trading day initialized. Equity baseline: ", g_startOfDayEquity);
}
}
//+------------------------------------------------------------------+
//| Container: Enforce Hard Floor, Goal Ceiling, and Time Windows |
//+------------------------------------------------------------------+
void EnforceContainerLimits()
{
double dailyPnLPct = ((AccountEquity() - g_startOfDayEquity) / g_startOfDayEquity) * 100.0;
// 1. Hard Floor / Hard Ceiling Checks
if(!g_tradingHalted)
{
if(dailyPnLPct <= -InpMaxDailyLossPct)
{
Print("[Container] Hard floor hit (", DoubleToString(dailyPnLPct, 2), "%). Liquidating positions.");
g_tradingHalted = true;
CloseAllPositions();
}
else if(dailyPnLPct >= InpDailyGoalPct)
{
Print("[Container] Goal reached (", DoubleToString(dailyPnLPct, 2), "%). Desk closed.");
g_tradingHalted = true;
CloseAllPositions();
}
}
// 2. Session Time Enforcement
if(!IsInSession() && CountBotPositions() > 0)
{
Print("[Container] End of trading window. Session liquidated.");
CloseAllPositions();
}
}
//+------------------------------------------------------------------+
//| Container: Session Filter Validator |
//+------------------------------------------------------------------+
bool IsInSession()
{
datetime now = TimeCurrent();
int currentSeconds = TimeHour(now) * 3600 + TimeMinute(now) * 60 + TimeSeconds(now);
int startSeconds = ParseTimeToSeconds(InpSessionStart);
int endSeconds = ParseTimeToSeconds(InpSessionEnd);
if(startSeconds <= endSeconds)
return (currentSeconds >= startSeconds && currentSeconds <= endSeconds);
else
return (currentSeconds >= startSeconds || currentSeconds <= endSeconds); // Overnight span
}
int ParseTimeToSeconds(string timeStr)
{
string parts[];
ushort u_sep = StringGetCharacter(":", 0);
int count = StringSplit(timeStr, u_sep, parts);
if(count >= 2)
return (int)StringToInteger(parts[0]) * 3600 + (int)StringToInteger(parts[1]) * 60;
return 0;
}
//+------------------------------------------------------------------+
//| Bricks: M1/M5 Scalp Execution |
//+------------------------------------------------------------------+
void ExecuteBricks()
{
if(g_tradingHalted || !IsInSession())
return;
double fastPrev = iMA(Symbol(), 0, InpFastEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double fastCurr = iMA(Symbol(), 0, InpFastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double slowPrev = iMA(Symbol(), 0, InpSlowEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double slowCurr = iMA(Symbol(), 0, InpSlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
bool longSignal = (fastPrev <= slowPrev && fastCurr > slowCurr);
bool shortSignal = (fastPrev >= slowPrev && fastCurr < slowCurr);
if(longSignal)
{
ClosePositionsByType(OP_SELL);
if(CountBotPositions() == 0)
OrderSend(Symbol(), OP_BUY, InpLotSize, Ask, InpSlippage, 0, 0, "RiskContainer", InpMagicNumber, 0, clrBlue);
}
else if(shortSignal)
{
ClosePositionsByType(OP_BUY);
if(CountBotPositions() == 0)
OrderSend(Symbol(), OP_SELL, InpLotSize, Bid, InpSlippage, 0, 0, "RiskContainer", InpMagicNumber, 0, clrRed);
}
}
//+------------------------------------------------------------------+
//| Order Liquidation Helpers |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
if(OrderType() == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, InpSlippage, clrGray);
else if(OrderType() == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, InpSlippage, clrGray);
}
}
}
}
void ClosePositionsByType(int type)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber && OrderType() == type)
{
double price = (type == OP_BUY) ? Bid : Ask;
OrderClose(OrderTicket(), OrderLots(), price, InpSlippage, clrGray);
}
}
}
}
int CountBotPositions()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| On-Chart HUD |
//+------------------------------------------------------------------+
void UpdateDashboard()
{
double dailyPnLPct = ((AccountEquity() - g_startOfDayEquity) / g_startOfDayEquity) * 100.0;
string status = "ACTIVE";
if(g_tradingHalted)
{
if(dailyPnLPct >= InpDailyGoalPct) status = "GOAL REACHED (DESK CLOSED)";
else status = "MAX LOSS HIT (DESK CLOSED)";
}
else if(!IsInSession())
{
status = "OUT OF SESSION";
}
string dash = StringConcatenate(
"-----------------------------------------\n",
" THE RISK CONTAINER (MT4)\n",
" Daily Baseline: $", DoubleToString(g_startOfDayEquity, 2), "\n",
" Current PnL: ", DoubleToString(dailyPnLPct, 2), "%\n",
" Status: ", status, "\n",
"-----------------------------------------"
);
Comment(dash);
}