Page 2 of 2

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:30 pm
by PTScalper
Key Setup & Engine Differences

Spread Filter Omission: Because Pine Script pulls standard broker feeds built on the Last or Bid price depending on the exchange, you cannot reliably measure dynamic spread widening outside of Asian sessions natively in the code. You will need to manually check order book conditions when the alert fires.

Visual Feedback: The script shades the chart automatically when price breaches your defined "Trigger Distance" (e.g., 20 pips away from the HKMA limits), giving you a quick visual on the 15-minute chart of when the artificial order flow is likely stepping in.

Alerting Flexibility: I included both alertcondition() and alert().

alertcondition() gives you selectable conditions in the TradingView alert dropdown.

alert() handles dynamic string building. If you decide to route this to MT4/MT5 or cTrader using a webhook service like PineConnector, you can swap out the text string in the alert() function with your specific JSON payload or syntax string.

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:34 pm
by PTScalper
Because MetaTrader gives you direct, tick-by-tick access to the broker's raw Bid/Ask spread, we can fully replicate the liquidity filter that Pine Script was missing. For exotics like USD/HKD or USD/SGD, brokers frequently use 4 or 5 decimal places, so both EAs below automatically detect your broker's digit structure to normalize PipSize and correctly calculate the trigger distances and max spread limits.

MT5 (MQL5) Expert Advisor

The MQL5 version uses the standard #include <Trade\Trade.mqh> library for clean execution. Place this in MQL5\Experts.

Code: Select all

//+------------------------------------------------------------------+
//|                                        PegRegimeReversionMT5.mq5 |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>

enum ENUM_OPERATING_MODE {
    MODE_ALERT_ONLY = 0, // Alert Only
    MODE_AUTO_TRADE = 1  // Auto Trade
};

input ENUM_OPERATING_MODE OperatingMode = MODE_ALERT_ONLY; // Operating Mode
input double UpperPegBand = 7.8500; // Upper Peg Band
input double LowerPegBand = 7.7500; // Lower Peg Band
input double TriggerDistancePips = 20.0; // Trigger Distance (Pips)
input double MaxSpreadPips = 50.0; // Max Allowed Spread (Pips)
input double TradeLots = 1.0; // Volume (Lots)
input double StopLossPips = 100.0; // Stop Loss (Pips)
input double TakeProfitPips = 400.0; // Take Profit (Pips)
input ulong MagicNumber = 123456;

CTrade trade;
double PipSize;
int PipMultiplier;
datetime lastAlertTime;

int OnInit() {
    // Dynamically adjust for 4/5 digit brokers
    PipMultiplier = (_Digits == 5 || _Digits == 3) ? 10 : 1;
    PipSize = _Point * PipMultiplier;
    
    trade.SetExpertMagicNumber(MagicNumber);
    lastAlertTime = 0;
    return(INIT_SUCCEEDED);
}

void OnTick() {
    double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    
    // Spread in MQL5 is returned in points, so we divide by our PipMultiplier
    long spreadPoints = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    double currentSpreadPips = (double)spreadPoints / PipMultiplier;

    // Calculate distance to HKMA/MAS boundaries
    double distanceToUpperPips = (UpperPegBand - currentBid) / PipSize;
    double distanceToLowerPips = (currentAsk - LowerPegBand) / PipSize;

    bool nearUpperBand = (distanceToUpperPips <= TriggerDistancePips);
    bool nearLowerBand = (distanceToLowerPips <= TriggerDistancePips);

    if(!nearUpperBand && !nearLowerBand) return;

    // Filter out illiquid hours
    if(currentSpreadPips > MaxSpreadPips) {
        LogAlertOnce("Spread too wide (" + DoubleToString(currentSpreadPips, 1) + " pips). Skipping intervention setup.");
        return;
    }

    if(nearUpperBand) HandleSetup(ORDER_TYPE_SELL, "Near Upper Peg Boundary");
    else if(nearLowerBand) HandleSetup(ORDER_TYPE_BUY, "Near Lower Peg Boundary");
}

void HandleSetup(ENUM_ORDER_TYPE tradeType, string reason) {
    if(HasOpenPosition(tradeType == ORDER_TYPE_BUY ? POSITION_TYPE_BUY : POSITION_TYPE_SELL)) return;

    if(OperatingMode == MODE_ALERT_ONLY) {
        string dir = (tradeType == ORDER_TYPE_BUY) ? "BUY" : "SELL";
        LogAlertOnce("[" + reason + "] Valid setup for " + dir + ". Spread is acceptable.");
    } else {
        ExecuteTrade(tradeType);
    }
}

bool HasOpenPosition(ENUM_POSITION_TYPE type) {
    for(int i = PositionsTotal() - 1; i >= 0; i--) {
        ulong ticket = PositionGetTicket(i);
        if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber) {
            if(PositionGetInteger(POSITION_TYPE) == type) return true;
        }
    }
    return false;
}

void ExecuteTrade(ENUM_ORDER_TYPE type) {
    double price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double sl = 0, tp = 0;
    
    if(type == ORDER_TYPE_BUY) {
        sl = price - (StopLossPips * PipSize);
        tp = price + (TakeProfitPips * PipSize);
    } else {
        sl = price + (StopLossPips * PipSize);
        tp = price - (TakeProfitPips * PipSize);
    }
    
    sl = NormalizeDouble(sl, _Digits);
    tp = NormalizeDouble(tp, _Digits);
    
    if(type == ORDER_TYPE_BUY) {
        trade.Buy(TradeLots, _Symbol, price, sl, tp, "Peg Monitor");
    } else {
        trade.Sell(TradeLots, _Symbol, price, sl, tp, "Peg Monitor");
    }
}

void LogAlertOnce(string msg) {
    // Throttle alerts to once per 15 minutes to prevent spam during consolidation
    if(TimeCurrent() - lastAlertTime > 900) { 
        Print(msg);
        Alert(msg);
        lastAlertTime = TimeCurrent();
    }
}

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:34 pm
by PTScalper
MT4 (MQL4) Expert Advisor

The MQL4 version relies directly on the legacy OrderSend execution model and MarketInfo calls. Place this in MQL4\Experts.

Code: Select all

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

enum ENUM_OPERATING_MODE {
    MODE_ALERT_ONLY = 0, // Alert Only
    MODE_AUTO_TRADE = 1  // Auto Trade
};

input ENUM_OPERATING_MODE OperatingMode = MODE_ALERT_ONLY; // Operating Mode
input double UpperPegBand = 7.8500; // Upper Peg Band
input double LowerPegBand = 7.7500; // Lower Peg Band
input double TriggerDistancePips = 20.0; // Trigger Distance (Pips)
input double MaxSpreadPips = 50.0; // Max Allowed Spread (Pips)
input double TradeLots = 1.0; // Volume (Lots)
input double StopLossPips = 100.0; // Stop Loss (Pips)
input double TakeProfitPips = 400.0; // Take Profit (Pips)
input int MagicNumber = 123456;

double PipSize;
int PipMultiplier;
datetime lastAlertTime;

int OnInit() {
    PipMultiplier = (_Digits == 5 || _Digits == 3) ? 10 : 1;
    PipSize = Point * PipMultiplier;
    lastAlertTime = 0;
    return(INIT_SUCCEEDED);
}

void OnTick() {
    double currentAsk = Ask;
    double currentBid = Bid;
    
    // Spread in MT4 is returned in Points, convert to standard Pips
    double currentSpreadPips = MarketInfo(Symbol(), MODE_SPREAD) / (double)PipMultiplier;

    double distanceToUpperPips = (UpperPegBand - currentBid) / PipSize;
    double distanceToLowerPips = (currentAsk - LowerPegBand) / PipSize;

    bool nearUpperBand = (distanceToUpperPips <= TriggerDistancePips);
    bool nearLowerBand = (distanceToLowerPips <= TriggerDistancePips);

    if(!nearUpperBand && !nearLowerBand) return;

    if(currentSpreadPips > MaxSpreadPips) {
        LogAlertOnce("Spread too wide (" + DoubleToString(currentSpreadPips, 1) + " pips). Skipping setup.");
        return;
    }

    if(nearUpperBand) HandleSetup(OP_SELL, "Near Upper Peg Boundary");
    else if(nearLowerBand) HandleSetup(OP_BUY, "Near Lower Peg Boundary");
}

void HandleSetup(int tradeType, string reason) {
    if(HasOpenPosition(tradeType)) return;

    if(OperatingMode == MODE_ALERT_ONLY) {
        string dir = (tradeType == OP_BUY) ? "BUY" : "SELL";
        LogAlertOnce("[" + reason + "] Valid setup for " + dir + ".");
    } else {
        ExecuteTrade(tradeType);
    }
}

bool HasOpenPosition(int type) {
    for(int i = OrdersTotal() - 1; i >= 0; i--) {
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
            if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == type) {
                return true;
            }
        }
    }
    return false;
}

void ExecuteTrade(int type) {
    double price = (type == OP_BUY) ? Ask : Bid;
    double sl = 0, tp = 0;
    
    if(type == OP_BUY) {
        sl = price - (StopLossPips * PipSize);
        tp = price + (TakeProfitPips * PipSize);
    } else {
        sl = price + (StopLossPips * PipSize);
        tp = price - (TakeProfitPips * PipSize);
    }
    
    sl = NormalizeDouble(sl, Digits);
    tp = NormalizeDouble(tp, Digits);
    
    // Send order
    int ticket = OrderSend(Symbol(), type, TradeLots, price, 3, sl, tp, "Peg Monitor", MagicNumber, 0, (type==OP_BUY)?clrBlue:clrRed);
    if(ticket < 0) {
        Print("OrderSend failed with error #", GetLastError());
    }
}

void LogAlertOnce(string msg) {
    if(TimeCurrent() - lastAlertTime > 900) { // Throttle: 15 minutes
        Print(msg);
        Alert(msg);
        lastAlertTime = TimeCurrent();
    }
}

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:34 pm
by PTScalper
Since the daily/15-minute price action you prefer observing is highly sensitive to the exact moment intervention happens, running either of these on a VPS in MODE_ALERT_ONLY will push desktop notifications (and push notifications to your phone if you have MetaQuotes ID configured) exactly when the setup conditions align and the spread is organically tight.

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:35 pm
by PTScalper
To log order rejections directly to a CSV, you need to capture the exact return code (retcode) from the CTrade execution result, parse it, and append the transaction details using MQL5's native file handling functions.

During central bank interventions, brokers frequently reject orders with specific server-side codes like 10006 (Request rejected), 10016 (Invalid Stops - usually caused by instant spread widening eating the stop loss), or 10012 (Request rejected by dealer).

Here are the two functions to update/add in your MT5 script.

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:35 pm
by PTScalper
1. Update the ExecuteTrade Function

Modify the existing execution block to evaluate the boolean return of the trade.Buy() or trade.Sell() methods. If it returns false, extract the rejection details and pass them to the logging function.

Code: Select all

void ExecuteTrade(ENUM_ORDER_TYPE type) {
    double price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double sl = 0, tp = 0;
    
    if(type == ORDER_TYPE_BUY) {
        sl = price - (StopLossPips * PipSize);
        tp = price + (TakeProfitPips * PipSize);
    } else {
        sl = price + (StopLossPips * PipSize);
        tp = price - (TakeProfitPips * PipSize);
    }
    
    sl = NormalizeDouble(sl, _Digits);
    tp = NormalizeDouble(tp, _Digits);
    
    bool executionSuccess = false;
    
    if(type == ORDER_TYPE_BUY) {
        executionSuccess = trade.Buy(TradeLots, _Symbol, price, sl, tp, "Peg Monitor");
    } else {
        executionSuccess = trade.Sell(TradeLots, _Symbol, price, sl, tp, "Peg Monitor");
    }

    // Capture and log the rejection if the trade fails
    if(!executionSuccess) {
        uint retcode = trade.ResultRetcode();
        string retcodeDesc = trade.ResultRetcodeDescription();
        string tradeDir = (type == ORDER_TYPE_BUY) ? "BUY" : "SELL";
        
        PrintFormat("Trade Rejected: %s | Code: %d", retcodeDesc, retcode);
        LogRejectionToCSV(tradeDir, price, retcode, retcodeDesc);
    }
}

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:35 pm
by PTScalper
2. Add the LogRejectionToCSV Function

This function opens (or creates) a CSV file, seeks the end of the file to prevent overwriting historical data, writes the headers if the file is new, and logs the tick data at the exact moment of rejection.

Code: Select all

void LogRejectionToCSV(string tradeDir, double price, uint retcode, string retcodeDesc) {
    string fileName = "PegMonitor_Rejections.csv";
    
    // Open file for read/write. Create if it doesn't exist. Use CSV format with ANSI encoding.
    int fileHandle = FileOpen(fileName, FILE_CSV | FILE_READ | FILE_WRITE | FILE_ANSI, ",");
    
    if(fileHandle != INVALID_HANDLE) {
        // Move the file pointer to the end of the file to append data
        FileSeek(fileHandle, 0, SEEK_END);
        
        // If the file is newly created (size is 0), write the header row first
        if(FileSize(fileHandle) == 0) {
            FileWrite(fileHandle, "Timestamp", "Symbol", "Direction", "Volume", "Requested Price", "Spread (Pips)", "RetCode", "Rejection Reason");
        }
        
        // Calculate the spread at the exact moment of rejection
        long spreadPoints = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
        double currentSpreadPips = (double)spreadPoints / PipMultiplier;
        
        // Append the rejection data
        FileWrite(fileHandle, 
                  TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS),
                  _Symbol,
                  tradeDir,
                  DoubleToString(TradeLots, 2),
                  DoubleToString(price, _Digits),
                  DoubleToString(currentSpreadPips, 1),
                  IntegerToString(retcode),
                  retcodeDesc);
                  
        // Always close the handle to free the file lock
        FileClose(fileHandle);
    } else {
        Print("Failed to open CSV file for writing. Error code: ", GetLastError());
    }
}

Re: Asian Dollar Pairs: SGD, HKD, and What Managed Regimes Mean for Traders

Posted: Mon Oct 05, 2026 4:36 pm
by PTScalper
Where to Find the Output Data

For security reasons, the MT5 sandbox restricts all file operations to a specific folder.

1.) Open your MT5 Terminal.

2.) Go to File > Open Data Folder.

3.) Navigate to MQL5 > Files.

4.) You will find PegMonitor_Rejections.csv there.

By logging the Spread (Pips) at the exact millisecond of the rejection alongside the RetCode, you can empirically verify if your broker is pulling liquidity (resulting in an off-quotes error or blown stop-loss parameters) or if the order routing itself is being suspended during the central bank intervention.