Stop Trading Today when Loss or Consecutive Loss

[Deleted]  

I am trying to add Loss control to my EA.


1. it will stop taking new trade ones it hit X amount in loss Today and will restart taking new trade tomorrow. 

void TodayLossControling()
  {
// ================================
// 1. Calculate start of current day
// ================================
   datetime nowDayStart = StrToTime(TimeToString(TimeCurrent(), TIME_DATE));

// New day detected → reset EA
   if(nowDayStart != TodayDate)
     {
      TodayDate = nowDayStart;
      TodayLossEAPaused = false;
     }

// ================================
// 2. Today's total P/L calculation
// ================================
   double todayPL = 0;

   int totalHistory = OrdersHistoryTotal();
   for(int i = totalHistory - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
        {
         if(OrderMagicNumber() == Magic && OrderCloseTime() >= nowDayStart)
           {
            todayPL += OrderProfit() + OrderSwap() + OrderCommission();
           }
        }
     }

// ================================
// 3. Pause EA when daily loss reached
// ================================
   if(TodayCutLossType == BalancePercentage)
      gTodayLossPL =(AccountBalance() * (TodayMaxLoss * 0.01));
   else
      gTodayLossPL = TodayMaxLoss;
   if(!TodayLossEAPaused && todayPL <= -MathAbs(gTodayLossPL))
      TodayLossEAPaused = true;
  }

2. It will stop taking new trade after X loss trade in sequence 


void CheckConsecutiveLossControl()
  {
   // Get today's date at 00:00
   datetime today = StrToTime(TimeToString(TimeCurrent(), TIME_DATE));

   // --- Reset on New Day ---
   if(today != LastResetDay)
     {
      ConsecutiveLoss      = 0;
      ConsecutiveLossPaused = false;     // allow trading again
      LastResetDay         = today;
      lastCountedCloseTime = 0;          // reset order tracking too

      Print("restarted the new trades");
     }

   // --- Update Consecutive Loss Counter ---
   // Check last *new* closed order
   for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         continue;

      if(OrderMagicNumber() != Magic)
         continue;

      // only process orders closed after lastCountedCloseTime
      if(OrderCloseTime() <= lastCountedCloseTime)
         continue;

      // Only count today's orders (after reset)
      if(OrderCloseTime() > LastResetDay)
        {
         if(OrderProfit() < 0)
            ConsecutiveLoss++;
         else
            ConsecutiveLoss = 0;
        }

      // remember last processed close time
      lastCountedCloseTime = OrderCloseTime();
      break;
     }

   // --- Check if loss limit reached ---
   if(!ConsecutiveLossPaused && ConsecutiveLoss >= continueTradeLoss)
      ConsecutiveLossPaused = true;
  }

Is i am doing correct? 

[Deleted]  
Ryan L Johnson #:
I don't see your variable declarations
extern string __LossControl__ = "***Loss Control***";
extern bool   TodayLossControl = true;
enum FixedVsBalancePercentage_enum {FixedMoney, BalancePercentage};
extern FixedVsBalancePercentage_enum TodayCutLossType = BalancePercentage;
extern double TodayMaxLoss        = 1;
extern int continueTradeLoss = 5;

int ConsecutiveLoss = 0;
bool TodayLossEAPaused = false, ConsecutiveLossPaused = false;
datetime TodayDate;
datetime LastResetDay = 0, lastCountedCloseTime = 0;

int OnInit()
{
TodayDate = StrToTime(TimeToString(TimeCurrent(), TIME_DATE));
return(INIT_SUCCEEDED);
}


Ryan L Johnson #:
TimeLocal() returns GMT in the Tester. TimeCurrent() returns GMT+/- per the historic data timestamps during bactesting.
Thanks for this data. 
 
Comments that do not relate to this topic, have been moved to "Simulating time in the MT4 tester and whether it is necessary to cast datetime to long".
 
anuj71:
Is i am doing correct? 

This is not a very correct question. Either your code works as you expect, or it doesn't.

anuj71:
// ================================
// 1. Calculate start of current day
// ================================
   datetime nowDayStart = StrToTime(TimeToString(TimeCurrent(), TIME_DATE));

This is not quite on topic, but it catches the eye. I personally calculate the start time of the day like this:

#define _secsInDay 86400
#define _calculDayStartDt(a) (((a) / _secsInDay) * _secsInDay)

void OnStart()
  {
   datetime timeCurrent = TimeCurrent();
   datetime dayStartDt = _calculDayStartDt(timeCurrent);
  }
 
anuj71:

I am trying to add Loss control to my EA.

1. it will stop taking new trade ones it hit X amount in loss Today and will restart taking new trade tomorrow.

void TodayLossControling()
  {
   int totalHistory = OrdersHistoryTotal();
   for(int i = totalHistory - 1; i >= 0; i--)
     {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))

2. It will stop taking new trade after X loss trade in sequence 

void CheckConsecutiveLossControl()
  {
   for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         continue;

The second thing that immediately catches my eye is that you have two different functions that analyze the entire order history. Perhaps it makes sense to prepare all the necessary information from the order history once, instead of looping through the entire order history several times per tick.

 
Vladislav Boyko #:

The second thing that immediately catches my eye is that you have two different functions that analyze the entire order history. Perhaps it makes sense to prepare all the necessary information from the order history once, instead of looping through the entire order history several times per tick.

It is better to avoid even a single analysis of the entire history (with each tick). But first, try to get by with at least one cycle through the order history, and not several.
[Deleted]  
Vladislav Boyko #:
The second thing that immediately catches my eye is that you have two different functions that analyze the entire order history. Perhaps it makes sense to prepare all the necessary information from the order history once, instead of looping through the entire order history several times per tick.

Here is updated code from your suggestion, i am looping one time per tick (order history) and i am using #define like you mentioned 

//+------------------------------------------------------------------+
//|                    LOSS CONTROL SYSTEM                           |
//+------------------------------------------------------------------+

// ---- INPUTS ----
extern string __LossControl__ = "***Loss Control***";
extern bool   TodayLossControl = true;

enum FixedVsBalancePercentage_enum {FixedMoney, BalancePercentage};
extern FixedVsBalancePercentage_enum TodayCutLossType = BalancePercentage;

extern double TodayMaxLoss        = 1;    // % or fixed money
extern int    ConsecutiveTradeLoss = 5;   // max consecutive losing trades

extern int Magic = 12345;

// ---- INTERNAL VARIABLES ----
int ConsecutiveLoss = 0;
bool TodayLossEAPaused = false;
bool ConsecutiveLossPaused = false;

datetime TodayDate;
datetime LastResetDay = 0;
datetime lastCountedCloseTime = 0;

double gTodayLossPL = 0;

// ---- DAY START MACRO (FAST) ----
#define _secsInDay 86400
#define DayStart(a) (((a) / _secsInDay) * _secsInDay)


//+------------------------------------------------------------------+
//|   STRUCT TO STORE HISTORY RESULTS                               |
//+------------------------------------------------------------------+
struct HistoryInfo
  {
   double todayPL;
   int consecutiveLoss;
   datetime lastCloseTime;
  };
HistoryInfo hist;


//+------------------------------------------------------------------+
//|   INITIALIZATION                                                 |
//+------------------------------------------------------------------+
int OnInit()
{
   TodayDate = DayStart(TimeCurrent());
   LastResetDay = TodayDate;
   return(INIT_SUCCEEDED);
}


//+------------------------------------------------------------------+
//|   ONE PASS ORDER HISTORY ANALYSIS                               |
//+------------------------------------------------------------------+
void AnalyzeOrderHistory()
{
   hist.todayPL         = 0;
   hist.consecutiveLoss = ConsecutiveLoss; // keep old value
   hist.lastCloseTime   = lastCountedCloseTime;

   datetime now         = TimeCurrent();
   datetime todayStart  = DayStart(now);

   int losses           = ConsecutiveLoss;
   datetime lastTime    = lastCountedCloseTime;

   for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         continue;

      if(OrderMagicNumber() != Magic)
         continue;

      datetime closeTime = OrderCloseTime();

      // ---- Today P/L ----
      if(closeTime >= todayStart)
         hist.todayPL += OrderProfit() + OrderSwap() + OrderCommission();

      // ---- Consecutive Loss Tracking ----
      if(closeTime > lastTime) // new order detected
        {
         if(closeTime > LastResetDay)
           {
            if(OrderProfit() < 0)
               losses++;
            else
               losses = 0;
           }

         lastTime = closeTime;
        }
     }

   // Update struct outputs
   hist.consecutiveLoss = losses;
   hist.lastCloseTime   = lastTime;
}


//+------------------------------------------------------------------+
//|   TODAY LOSS CONTROL                                             |
//+------------------------------------------------------------------+
void TodayLossControlling()
{
   if(TodayMaxLoss <= 0)
      return;

   datetime nowDayStart = DayStart(TimeCurrent());

   // --- New Day Reset ---
   if(nowDayStart != TodayDate)
     {
      TodayDate = nowDayStart;
      TodayLossEAPaused = false;
     }

   double todayPL = hist.todayPL;

   // Determine loss threshold
   if(TodayCutLossType == BalancePercentage)
      gTodayLossPL = AccountBalance() * (TodayMaxLoss * 0.01);
   else
      gTodayLossPL = TodayMaxLoss;

   // Pause EA if loss reached
   if(!TodayLossEAPaused && todayPL <= -MathAbs(gTodayLossPL))
      TodayLossEAPaused = true;
}


//+------------------------------------------------------------------+
//|   CONSECUTIVE LOSS CONTROL                                       |
//+------------------------------------------------------------------+
void CheckConsecutiveLossControl()
{
   if(ConsecutiveTradeLoss <= 0)
      return;

   datetime today = DayStart(TimeCurrent());

   // ---- Reset on New Day ----
   if(today != LastResetDay)
     {
      ConsecutiveLoss       = 0;
      ConsecutiveLossPaused = false;
      LastResetDay          = today;
      lastCountedCloseTime  = 0;
     }

   // Update counters from history scan
   ConsecutiveLoss       = hist.consecutiveLoss;
   lastCountedCloseTime  = hist.lastCloseTime;

   // Pause if limit exceeded
   if(!ConsecutiveLossPaused && ConsecutiveLoss >= ConsecutiveTradeLoss)
      ConsecutiveLossPaused = true;
}


//+------------------------------------------------------------------+
//|   MAIN RUNTIME                                                   |
//+------------------------------------------------------------------+
void OnTick()
{
   // Analyze history ONCE per tick
   AnalyzeOrderHistory();

   // Apply risk controls
   TodayLossControlling();
   CheckConsecutiveLossControl();

   // --- Check blocking conditions before placing trades ---
   if(TodayLossEAPaused || ConsecutiveLossPaused)
     {
      return;
     }
}


Vladislav Boyko #:
It is better to avoid even a single analysis of the entire history (with each tick).


Then what is the solution?. How to add Risk Management like Consecutive Loss Orders and Maximum today loss can be taken? 

 
anuj71 #:
Consecutive Loss Orders
anuj71:

It will stop taking new trade after X loss trade in sequence 

When analyzing your order history, you should collect all of today's orders into an array of structures (or classes) sorted by order close time. The structure/class must contain at least 2 fields (order closing time and profit):

class CHistOrder
  {
public:
   datetime orderCloseTime;
   double   orderProfit;
  };
[edit] You can then identify X losses in a row simply by looking at the profit value for the last X elements of the array (which is not at all difficult if you have a sorted array ready).
 

Let me clarify.

anuj71 #:

   for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         continue;

      if(OrderMagicNumber() != Magic)
         continue;

      datetime closeTime = OrderCloseTime();

      // ---- Today P/L ----
      if(closeTime >= todayStart)
         hist.todayPL += OrderProfit() + OrderSwap() + OrderCommission();

      // ---- Consecutive Loss Tracking ----
      if(closeTime > lastTime) // new order detected
        {
         if(closeTime > LastResetDay)
           {
            if(OrderProfit() < 0)
               losses++;
            else
               losses = 0;
           }

         lastTime = closeTime;
        }
     }

   // Update struct outputs
   hist.consecutiveLoss = losses;
   hist.lastCloseTime   = lastTime;
}

In theory, such code might work somewhat, but only on the condition that the orders in the terminal history are sorted by closing time (I have not tested your specific code).

I don't know how orders are sorted in MT4 history. If I need a specific sorting, I don't rely on the defaults and sort the orders myself.

[Deleted]  
Vladislav Boyko #:
When analyzing your order history, you should collect all of today's orders into an array of structures (or classes) sorted by order close time. The structure/class must contain at least 2 fields (order closing time and profit):
Vladislav Boyko #:
I don't know how orders are sorted in MT4 history. If I need a specific sorting, I don't rely on the defaults and sort the orders myself.

Add Class and sorting by close time 

//+------------------------------------------------------------------+
//|                    LOSS CONTROL SYSTEM                           |
//+------------------------------------------------------------------+

extern string __LossControl__ = "***Loss Control***";
extern bool   TodayLossControl = true;

enum FixedVsBalancePercentage_enum {FixedMoney, BalancePercentage};
extern FixedVsBalancePercentage_enum TodayCutLossType = BalancePercentage;

extern double TodayMaxLoss        = 1;
extern int    ConsecutiveTradeLoss = 5;
extern int    Magic = 12345;

// ---- Internal ----
bool TodayLossEAPaused = false;
bool ConsecutiveLossPaused = false;

datetime TodayDate;
datetime LastResetDay = 0;
double gTodayLossPL = 0;

// ---- Day start ----
#define _secsInDay 86400
#define DayStart(a) (((a) / _secsInDay) * _secsInDay)


//====================================================
//  Order Structure
//====================================================
class CHistOrder
{
public:
   datetime orderCloseTime;
   double   orderProfit;
};

// Sorting comparator
int sortByCloseTime(const CHistOrder &a, const CHistOrder &b)
{
   if(a.orderCloseTime < b.orderCloseTime) return -1;
   if(a.orderCloseTime > b.orderCloseTime) return  1;
   return 0;
}


//+------------------------------------------------------------------+
//|   INITIALIZATION                                                 |
//+------------------------------------------------------------------+
int OnInit()
{
   TodayDate = DayStart(TimeCurrent());
   LastResetDay = TodayDate;
   return(INIT_SUCCEEDED);
}


//+------------------------------------------------------------------+
//|   SCAN HISTORY → BUILD SORTED ARRAY                             |
//+------------------------------------------------------------------+
void BuildTodayOrdersArray(CHistOrder &arr[])
{
   ArrayResize(arr, 0);
   datetime todayStart = DayStart(TimeCurrent());

   int count = 0;

   for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
     {
      if(!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
         continue;
      if(OrderMagicNumber() != Magic)
         continue;

      datetime ct = OrderCloseTime();
      if(ct < todayStart) 
         continue;

      // Add order
      CHistOrder o;
      o.orderCloseTime = ct;
      o.orderProfit    = OrderProfit() + OrderSwap() + OrderCommission();

      ArrayResize(arr, count + 1);
      arr[count] = o;
      count++;
     }

   // Sort by close time
   if(count > 1)
      ArraySort(arr, WHOLE_ARRAY, 0, SORT_CUSTOM, sortByCloseTime);
}


//+------------------------------------------------------------------+
//|   TODAY LOSS CONTROL                                             |
//+------------------------------------------------------------------+
void TodayLossControlling(double todayPL)
{
   if(TodayMaxLoss <= 0)
      return;

   datetime nowDayStart = DayStart(TimeCurrent());

   // New Day → reset
   if(nowDayStart != TodayDate)
     {
      TodayDate = nowDayStart;
      TodayLossEAPaused = false;
     }

   // daily limit
   if(TodayCutLossType == BalancePercentage)
      gTodayLossPL = AccountBalance() * (TodayMaxLoss * 0.01);
   else
      gTodayLossPL = TodayMaxLoss;

   // Pause EA
   if(!TodayLossEAPaused && todayPL <= -MathAbs(gTodayLossPL))
      TodayLossEAPaused = true;
}


//+------------------------------------------------------------------+
//|   CONSECUTIVE LOSS CONTROL                                       |
//+------------------------------------------------------------------+
void CheckConsecutiveLossControl(CHistOrder &arr[])
{
   if(ConsecutiveTradeLoss <= 0)
      return;

   datetime today = DayStart(TimeCurrent());

   // New day reset
   if(today != LastResetDay)
     {
      ConsecutiveLossPaused = false;
      LastResetDay = today;
     }

   // Count losses in a row from END
   int lossCount = 0;
   int total = ArraySize(arr);

   for(int i = total - 1; i >= 0; i--)
     {
      if(arr[i].orderProfit < 0)
         lossCount++;
      else
         break;
     }

   if(!ConsecutiveLossPaused && lossCount >= ConsecutiveTradeLoss)
      ConsecutiveLossPaused = true;
}


//+------------------------------------------------------------------+
//|   MAIN LOOP                                                      |
//+------------------------------------------------------------------+
void OnTick()
{
   CHistOrder todaysOrders[];
   BuildTodayOrdersArray(todaysOrders);

   // compute today's PL
   double todayPL = 0;
   for(int i=0; i < ArraySize(todaysOrders); i++)
      todayPL += todaysOrders[i].orderProfit;

   // Apply risk controls
   TodayLossControlling(todayPL);
   CheckConsecutiveLossControl(todaysOrders);

   // BLOCK trading if needed
   if(TodayLossEAPaused || ConsecutiveLossPaused)
      return;
}
 
anuj71 #:

Add Class and sorting by close time 

You should understand what you are doing.


You have a simple task - to collect today's orders into an array of structures/classes, sorted by the order closing price time.

Forum on trading, automated trading systems and testing trading strategies

Stop Trading Today when Loss or Consecutive Loss

Vladislav Boyko, 2025.12.01 11:13

class CHistOrder
  {
public:
   datetime orderCloseTime;
   double   orderProfit;
  };

Do your own research on this and show your attempt. If you use AI assistance, make sure the generated code compiles and performs its task correctly.