Page 3 of 3

Re: Shutdown drills for yen traders: a case study approach

Posted: Sun Oct 25, 2026 9:05 pm
by PTScalper
Here is the looping script:

Code: Select all

//+------------------------------------------------------------------+
//|                 CloseAll_RetryMaxSpread_JPY.mq5                  |
//+------------------------------------------------------------------+
#property strict

#include <Trade\Trade.mqh>

int MaxSpreadPoints = 500; 

void OnStart()
{
    CTrade trade;
    trade.SetDeviationInPoints(100); 
    
    // ==========================================
    // 1. DELETE PENDING ORDERS (IMMEDIATE WIPE)
    // ==========================================
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(ticket > 0)
        {
            string symbol = OrderGetString(ORDER_SYMBOL);
            if(StringFind(symbol, "JPY") >= 0)
            {
                trade.OrderDelete(ticket);
            }
        }
    }
    Print("All JPY pending orders deleted.");

    // ==========================================
    // 2. LOOP TO CLOSE POSITIONS
    // ==========================================
    int attempts = 0;
    
    // IsStopped() ensures the loop breaks if you manually remove the script or close MT5
    while(!IsStopped())
    {
        bool pendingJPYPositions = false;
        attempts++;
        
        for(int i = PositionsTotal() - 1; i >= 0; i--)
        {
            string symbol = PositionGetSymbol(i);
            
            if(StringFind(symbol, "JPY") >= 0)
            {
                long currentSpread = SymbolInfoInteger(symbol, SYMBOL_SPREAD);
                
                if(currentSpread > MaxSpreadPoints)
                {
                    // Flag that we still have JPY exposure due to spread
                    pendingJPYPositions = true; 
                    Print("Attempt ", attempts, ": Spread for ", symbol, " is ", currentSpread, " - Waiting...");
                    continue; 
                }
                
                ulong ticket = PositionGetTicket(i);
                if(ticket > 0)
                {
                    if(!trade.PositionClose(ticket))
                    {
                        // If the close fails (e.g., requote), flag to try again next loop
                        pendingJPYPositions = true;
                        Print("Attempt ", attempts, ": Failed to close ", symbol, ". Retrying...");
                    }
                    else
                    {
                        Print("Attempt ", attempts, ": Successfully closed ", symbol);
                    }
                }
            }
        }
        
        // If the loop finished and no JPY positions triggered the flag, we are flat.
        if(!pendingJPYPositions)
        {
            Alert("All JPY positions successfully closed and orders deleted.");
            break; 
        }
        
        // Sleep for 250 milliseconds before checking spreads again to prevent CPU overload
        Sleep(250); 
    }
}

Re: Shutdown drills for yen traders: a case study approach

Posted: Sun Oct 25, 2026 9:06 pm
by PTScalper
Critical Mechanics of the Polling Loop

The Sleep(250) Command: This is mandatory for infinite loops in MQL5. Without it, the while loop will execute thousands of times per second, immediately maxing out your CPU core and potentially freezing the MetaTrader terminal when you need it most. A 250-millisecond pause allows the platform to breathe and update price feeds.

The IsStopped() Safety: If the market completely breaks and the spread remains above your limit for hours, this script will run indefinitely on the chart. The !IsStopped() condition allows you to manually abort the script by right-clicking the chart and selecting "Remove Script" without crashing the platform.

The pendingJPYPositions Flag: This boolean resets to false at the start of every loop. If the script finds even one JPY position that it cannot close (due to spread or a server requote error), it flips the flag to true, forcing the while loop to run another cycle.

Re: Shutdown drills for yen traders: a case study approach

Posted: Sun Oct 25, 2026 9:06 pm
by PTScalper
To display real-time status updates directly on the chart, you can build a dynamic string inside your while loop and pass it to the Comment() function. This overwrites the text in the top-left corner of the chart on every cycle, giving you a live dashboard of which pairs are stuck and what their current spreads are.

Re: Shutdown drills for yen traders: a case study approach

Posted: Sun Oct 25, 2026 9:06 pm
by PTScalper
Here is the updated script featuring the real-time chart comment dashboard:

Code: Select all

//+------------------------------------------------------------------+
//|             CloseAll_RetryMaxSpread_Comment_JPY.mq5              |
//+------------------------------------------------------------------+
#property strict

#include <Trade\Trade.mqh>

int MaxSpreadPoints = 500; 

void OnStart()
{
    CTrade trade;
    trade.SetDeviationInPoints(100); 
    
    // ==========================================
    // 1. DELETE PENDING ORDERS 
    // ==========================================
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ulong ticket = OrderGetTicket(i);
        if(ticket > 0)
        {
            string symbol = OrderGetString(ORDER_SYMBOL);
            if(StringFind(symbol, "JPY") >= 0)
            {
                trade.OrderDelete(ticket);
            }
        }
    }

    // ==========================================
    // 2. LOOP TO CLOSE POSITIONS WITH UI
    // ==========================================
    int attempts = 0;
    
    while(!IsStopped())
    {
        bool pendingJPYPositions = false;
        attempts++;
        
        // Initialize the comment string for this loop cycle
        string statusText = "--- JPY EMERGENCY CLOSE ACTIVE ---\n";
        statusText += "Attempt: " + IntegerToString(attempts) + "\n\n";
        
        for(int i = PositionsTotal() - 1; i >= 0; i--)
        {
            string symbol = PositionGetSymbol(i);
            
            if(StringFind(symbol, "JPY") >= 0)
            {
                long currentSpread = SymbolInfoInteger(symbol, SYMBOL_SPREAD);
                
                if(currentSpread > MaxSpreadPoints)
                {
                    pendingJPYPositions = true; 
                    statusText += symbol + " | Spread: " + IntegerToString(currentSpread) + " (Limit: " + IntegerToString(MaxSpreadPoints) + ") -> WAITING\n";
                    continue; 
                }
                
                ulong ticket = PositionGetTicket(i);
                if(ticket > 0)
                {
                    if(!trade.PositionClose(ticket))
                    {
                        pendingJPYPositions = true;
                        statusText += symbol + " | Close Failed. Retrying...\n";
                    }
                    else
                    {
                        statusText += symbol + " | CLOSED SUCCESSFULLY\n";
                    }
                }
            }
        }
        
        // Print the built string to the top-left of the chart
        Comment(statusText);
        
        if(!pendingJPYPositions)
        {
            // Clear the comment from the chart when finished
            Comment(""); 
            Alert("All JPY positions successfully closed and orders deleted.");
            break; 
        }
        
        Sleep(250); 
    }
}

Re: Shutdown drills for yen traders: a case study approach

Posted: Sun Oct 25, 2026 9:07 pm
by PTScalper
Key UI Mechanics

Dynamic String Building: By declaring string statusText at the start of the while loop, you reset the display to a blank slate every 250 milliseconds. The for loop then appends (+=) the current status of every open JPY pair to that string before projecting it to the screen.

Comment vs. Print: The Print() function dumps text into the MT5 "Experts" or "Journal" tab, which creates thousands of log lines during a loop. Comment() is far superior for this specific use case because it updates a single overlay on your chart, keeping your platform clean while giving you immediate visual confirmation of the bottleneck.

The Cleanup: Calling Comment("") with an empty string right before the break command erases the text overlay once the script finishes its job.