//+------------------------------------------------------------------+ //| SaherElm IT Center MQL5 Expert Advisor | //| | //| Name: X121 XPV EA | //| Description: Multi-Timeframe Peak & Vale Breakout Strategy | //| Maintainer: Hadi Khazaee Asl | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property strict // #include "../Helpers/x-saherelm.x121.xpv.helper.mq5" // Input Parameters input double RiskPercent = 1.0; // Risk per trade in percentage input int StopLossPips = 50; // Stop Loss in pips input int TakeProfitPips = 100; // Take Profit in pips input bool UseTrailingStop = true; // Enable trailing stop input int TrailingStopPips = 30; // Trailing stop distance in pips input int MagicNumber = 123456; // Unique identifier for trades input bool DebugMode = true; // Enable debug messages // // Global Variables ... X121XPVInputs mXPVInputs; XCX121XPVHelper *mXPVHelper; //+------------------------------------------------------------------+ //| Expert Initialization Function | //+------------------------------------------------------------------+ int OnInit() { // // Attach the X121 XPV indicator ... mXPVInputs.Default(); mXPVHelper = new XCX121XPVHelper(); bool isInited = mXPVHelper.Init( _Symbol, _Period, mXPVInputs // ); if (!isInited) { return INIT_FAILED; } // Print("X121 XPV EA Initialized."); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert Deinitialization Function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // mXPVInputs.Clean(); ZeroMemory(mXPVHelper); Print("X121 XPV EA Deinitialized."); } //+------------------------------------------------------------------+ //| Expert Tick Function | //+------------------------------------------------------------------+ void OnTick() { // // Check if there are open positions for this symbol if (PositionSelect(_Symbol)) { ManageOpenPosition(); return; } // X121XPVConditions pvConditions; bool isRetrieved = mXPVHelper.GetConditions( pvConditions, 1 // ); if (!isRetrieved) { return; } // // Get indicator values double peak = pvConditions.peaksBuffer[0]; double vale = pvConditions.valesBuffer[0]; double peakGoldenZone = pvConditions.peaksGoldenBuffer[0]; double valeGoldenZone = pvConditions.valesGoldenBuffer[0]; // // Validate indicator values if (peak == EMPTY_VALUE || vale == EMPTY_VALUE || peakGoldenZone == EMPTY_VALUE || valeGoldenZone == EMPTY_VALUE) { // if (DebugMode) Print("Invalid indicator values. Skipping..."); return; } // // Entry Conditions double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // // Long Entry if (bid > peak && bid > peakGoldenZone) { OpenTrade(ORDER_TYPE_BUY, peak, valeGoldenZone); } // // Short Entry if (ask < vale && ask < valeGoldenZone) { OpenTrade(ORDER_TYPE_SELL, vale, peakGoldenZone); } } //+------------------------------------------------------------------+ //| Open a Trade | //+------------------------------------------------------------------+ void OpenTrade(int orderType, double entryLevel, double targetLevel) { // double lotSize = CalculateLotSize(entryLevel, targetLevel); double sl = (orderType == ORDER_TYPE_BUY) ? entryLevel - StopLossPips * Point() : entryLevel + StopLossPips * Point(); double tp = (orderType == ORDER_TYPE_BUY) ? entryLevel + TakeProfitPips * Point() : entryLevel - TakeProfitPips * Point(); // // Prepare trade request MqlTradeRequest request = {}; MqlTradeResult result = {}; // request.action = TRADE_ACTION_DEAL; request.symbol = _Symbol; request.volume = lotSize; request.type = (ENUM_ORDER_TYPE)orderType; request.price = (orderType == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); request.sl = sl; request.tp = tp; request.deviation = 10; request.magic = MagicNumber; // // Send trade request if (!OrderSend(request, result)) { Print("Trade failed: ", result.retcode); } else { Print("Trade opened successfully."); } } //+------------------------------------------------------------------+ //| Manage Open Position | //+------------------------------------------------------------------+ void ManageOpenPosition() { ulong ticket = PositionGetInteger(POSITION_TICKET); double currentPrice = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); // Trailing Stop Logic if (UseTrailingStop) { double newSL = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? currentPrice - TrailingStopPips * Point() : currentPrice + TrailingStopPips * Point(); if ((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && newSL > sl) || (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && newSL < sl)) { ModifyPosition(ticket, newSL, tp); } } } //+------------------------------------------------------------------+ //| Modify Position | //+------------------------------------------------------------------+ void ModifyPosition(ulong ticket, double newSL, double newTP) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_SLTP; request.position = ticket; request.sl = newSL; request.tp = newTP; if (!OrderSend(request, result)) { Print("Failed to modify position: ", result.retcode); } else { Print("Position modified successfully."); } } //+------------------------------------------------------------------+ //| Calculate Lot Size | //+------------------------------------------------------------------+ double CalculateLotSize(double entryLevel, double targetLevel) { double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100; double stopLossDistance = MathAbs(entryLevel - targetLevel) / Point(); double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double lotSize = riskAmount / (stopLossDistance * tickValue); // Normalize lot size double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); lotSize = MathFloor(lotSize / stepLot) * stepLot; lotSize = MathMax(minLot, MathMin(maxLot, lotSize)); return lotSize; }