Advertisement IC Markets

The 1% Rule Isn't Optional

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 1% Rule Isn't Optional

Post by PTScalper »

Institutional Mechanics of the Rescue Hedge

Index Mapping (failedIndexes): Task.WhenAll() guarantees that the resulting array remains in the exact order the tasks were added. By looping through the array index, you can safely pull the precise Position object from the original basket list that corresponds to the failed broker packet.

Hedging vs. Netting Accounts: cTrader supports two account types at the broker level.

Hedging Account: The broker will open a brand new opposite position. You will have two open positions on your ledger (e.g., Long GBPUSD and Short GBPUSD) effectively freezing your PnL.

Netting Account: Executing an opposing market order is actually the native way to close a position on a netting account. If the original ClosePositionAsync failed due to a platform routing error, bypassing it and sending a raw ExecuteMarketOrderAsync in the opposite direction frequently succeeds and nets the position out to 0.

Audit Trail Tagging: Notice the label is set to "RescueHedge" and the comment is tagged as $"Rescue_{basketId}". Because your ManageBaskets() loop filters out positions that do not start with "Arb_", the Master Robot will safely ignore this rescue hedge, preventing an infinite loop of it trying to manage the emergency position.
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 1% Rule Isn't Optional

Post by PTScalper »

Executing this in MQL4 requires a paradigm shift because MetaTrader 4 is strictly single-threaded and synchronous.

You cannot use async/await in MQL4. When you call OrderClose(), the entire Expert Advisor thread completely freezes. It sends the network packet to the broker and waits idly until the broker matching engine responds (which can take 20ms to 200ms depending on your VPS location). Only after receiving that response will MQL4 proceed to the next line of code to close Leg B.

While you cannot eliminate the client-side latency gap in MT4, you can implement the Rescue Protocol perfectly. MT4 is natively a hedging platform, meaning executing an opposing OrderSend() instantly locks the margin and floating PnL.
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 1% Rule Isn't Optional

Post by PTScalper »

Here is the exact algorithmic translation for the MT4 Basket Liquidator and Rescue Hedge.

Code: Select all

// =========================================================================
// MT4 SYNCHRONOUS BASKET LIQUIDATOR & RESCUE PROTOCOL
// =========================================================================
int RescueMagicNumber = 99999; // Dedicated magic number so the main EA ignores rescue trades

void LiquidateBasketWithRescue(string targetBasketId)
{
    // Must loop backwards in MQL4 when closing orders to prevent index shifting
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            // Check if the order comment matches the specific Basket ID
            if(StringFind(OrderComment(), targetBasketId) >= 0)
            {
                int ticket = OrderTicket();
                string sym = OrderSymbol();
                int type = OrderType();
                double lots = OrderLots();
                
                // Refresh rates to ensure we don't use stale Bid/Ask prices 
                // if the thread was frozen waiting for a previous Leg to close
                RefreshRates(); 
                
                double closePrice = (type == OP_BUY) ? MarketInfo(sym, MODE_BID) : MarketInfo(sym, MODE_ASK);
                
                // 1. Attempt Synchronous Broker Execution (Thread blocks here)
                bool closed = OrderClose(ticket, lots, closePrice, 10, clrWhite);
                
                if(closed)
                {
                    Print("[Basket Exit] Successfully liquidated ticket #", ticket, " for basket: ", targetBasketId);
                }
                else
                {
                    // 2. INITIATE RESCUE PROTOCOL
                    int err = GetLastError();
                    Print("[CRITICAL WARNING] Failed to close ticket #", ticket, " in basket ", targetBasketId, ". Error: ", err);
                    Print("[Rescue Protocol] Initiating instant opposing market order to neutralize delta.");
                    
                    int oppositeType = (type == OP_BUY) ? OP_SELL : OP_BUY;
                    double hedgePrice = (oppositeType == OP_BUY) ? MarketInfo(sym, MODE_ASK) : MarketInfo(sym, MODE_BID);
                    string rescueComment = "Rescue_" + targetBasketId;
                    
                    // 3. Execute opposing market order to lock PnL
                    int rescueTicket = OrderSend(sym, oppositeType, lots, hedgePrice, 10, 0, 0, rescueComment, RescueMagicNumber, 0, clrRed);
                    
                    if(rescueTicket > 0)
                    {
                        Print("[System Stabilized] Rescue hedge filled successfully (Ticket #", rescueTicket, "). Delta is perfectly neutral.");
                    }
                    else
                    {
                        int hedgeErr = GetLastError();
                        Print("[CATASTROPHIC ERROR] Rescue hedge ALSO failed. Error: ", hedgeErr, ". Portfolio exposed! Manual intervention required.");
                        // Trigger email/push notification here
                        SendNotification("URGENT: MT4 Rescue Hedge failed for basket " + targetBasketId);
                    }
                }
            }
        }
    }
}
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 1% Rule Isn't Optional

Post by PTScalper »

The Institutional Workarounds for MT4 Limitations

The RefreshRates() Imperative: In C# async architecture, all market orders use the exact same tick data because they fire concurrently. In MT4, if Leg A takes 150ms to close, the price of Leg B has actively changed in the background. If you do not explicitly call RefreshRates() immediately before fetching the MODE_BID/MODE_ASK for Leg B, the broker will reject the order with Error 138 (Requote) because your EA submitted a stale, 150ms-old price.

Slippage Tolerances: Notice the slippage parameter in OrderClose and OrderSend is set to 10 (points). In Stat Arb, because of the sequential delay, you must allow the broker wider slippage tolerance on the exit, otherwise the second leg will frequently bounce back with Requote errors, unnecessarily triggering your Rescue Protocol.

Loop Direction (Index Shifting): When parsing OrdersTotal(), you must write the for loop decrementally (i--). If you loop incrementally (i++), closing the order at index 0 forces the broker to slide the order at index 1 down into the 0 slot. Your loop then advances to index 1, entirely skipping the second leg of your basket.
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 1% Rule Isn't Optional

Post by PTScalper »

MetaTrader 5 introduces a massive architectural upgrade over MT4: the strict separation of Orders, Deals, and Positions.

Because MT5 tracks open trades as unified Positions rather than individual order tickets, the liquidation and rescue logic utilizes the standard CTrade library. However, MT5 execution introduces a new layer of complexity: Return Codes (Retcode). A function returning true in MT5 often only means the network packet reached the broker; you must explicitly verify TRADE_RETCODE_DONE to confirm the exchange matching engine actually filled the order.

Here is the MT5 Basket Liquidator and Rescue Protocol, optimized for Hedge-mode accounts.
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 1% Rule Isn't Optional

Post by PTScalper »

MQL5 pro version 1.00

Code: Select all

// =========================================================================
// MT5 BASKET LIQUIDATOR & RESCUE PROTOCOL
// =========================================================================
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>

CTrade         trade;            // Primary execution engine
CTrade         rescueTrade;      // Dedicated engine for emergency hedges
CPositionInfo  pos;              // Position state parser

ulong RescueMagicNumber = 99999;

// Call this inside OnInit()
void InitializeTradeEngines()
{
    trade.SetExpertMagicNumber(1337);
    rescueTrade.SetExpertMagicNumber(RescueMagicNumber);
    
    // Set slippage tolerance to prevent Requote (Error 10004) during sequential exits
    trade.SetDeviationInPoints(10);
    rescueTrade.SetDeviationInPoints(10);
    
    // Ensure synchronous execution so we can evaluate RetCodes instantly
    trade.SetAsyncMode(false); 
    rescueTrade.SetAsyncMode(false);
}

void LiquidateBasketWithRescue(string targetBasketId)
{
    // Loop backwards to prevent index shifting during liquidation
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if(pos.SelectByIndex(i))
        {
            // Verify the position belongs to the targeted basket
            if(StringFind(pos.Comment(), targetBasketId) >= 0)
            {
                ulong ticket = pos.Ticket();
                string sym = pos.Symbol();
                double vol = pos.Volume();
                ENUM_POSITION_TYPE type = pos.PositionType();
                
                // 1. Attempt Synchronous Broker Execution
                bool requestSent = trade.PositionClose(ticket);
                uint retCode = trade.ResultRetcode();
                
                // Verify both network transmission and exchange matching engine fill
                if(requestSent && (retCode == TRADE_RETCODE_DONE || retCode == TRADE_RETCODE_PLACED))
                {
                    Print("[Basket Exit] Successfully liquidated ticket #", ticket, " for basket: ", targetBasketId);
                }
                else
                {
                    // 2. INITIATE RESCUE PROTOCOL
                    Print("[CRITICAL WARNING] Failed to close ticket #", ticket, " in basket ", targetBasketId, ". RetCode: ", retCode);
                    Print("[Rescue Protocol] Initiating instant opposing market order to neutralize delta.");
                    
                    ENUM_ORDER_TYPE oppositeType = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
                    string rescueComment = "Rescue_" + targetBasketId;
                    
                    // Fetch real-time tick data for the hedge execution
                    CSymbolInfo symInfo;
                    symInfo.Name(sym);
                    symInfo.RefreshRates();
                    
                    double hedgePrice = (oppositeType == ORDER_TYPE_BUY) ? symInfo.Ask() : symInfo.Bid();
                    
                    // 3. Execute opposing market order to lock PnL
                    // Note: On an MT5 Hedging account, this opens a counter-position. 
                    // On an MT5 Netting account, this natively closes the original position.
                    bool rescued = rescueTrade.PositionOpen(sym, oppositeType, vol, hedgePrice, 0, 0, rescueComment);
                    uint hedgeRetCode = rescueTrade.ResultRetcode();
                    
                    if(rescued && (hedgeRetCode == TRADE_RETCODE_DONE || hedgeRetCode == TRADE_RETCODE_PLACED))
                    {
                        Print("[System Stabilized] Rescue hedge filled (Deal #", rescueTrade.ResultDeal(), "). Delta is perfectly neutral.");
                    }
                    else
                    {
                        Print("[CATASTROPHIC ERROR] Rescue hedge ALSO failed. RetCode: ", hedgeRetCode, ". Portfolio exposed! Manual intervention required.");
                        // Trigger push notification to mobile terminal
                        SendNotification("URGENT: MT5 Rescue Hedge failed for basket " + targetBasketId + ". RetCode: " + IntegerToString(hedgeRetCode));
                    }
                }
            }
        }
    }
}
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 1% Rule Isn't Optional

Post by PTScalper »

The MT5 Asynchronous Execution Edge (Zero-Ping Routing)

In the InitializeTradeEngines() function, I explicitly set trade.SetAsyncMode(false). This mirrors the MT4 sequential behavior so the script can read the ResultRetcode() immediately on the next line.

However, MT5 natively supports the exact zero-latency concurrent execution you utilized in cTrader via trade.SetAsyncMode(true).

If you enable Async mode, trade.PositionClose() fires the packet directly to your Network Interface Card in microseconds and returns true immediately without waiting for the broker to reply. This entirely eliminates client-side slippage on the exit.

The architectural trade-off is that in Async mode, you cannot check trade.ResultRetcode() on the next line. You must build a highly complex state machine using the OnTradeTransaction() event handler. The EA would fire the Async close requests, yield the thread, and wait for the broker matching engine to stream asynchronous TRADE_TRANSACTION_HISTORY_ADD events back to the terminal. If a rejection event streams in, the OnTradeTransaction() handler would dynamically catch it and trigger the rescueTrade execution on a separate thread process.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply