//+------------------------------------------------------------------+ //| X121_Strategy_EA.mq5 | //| Copyright 2023, SaherElm IT | //| https://saherelm.ir/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "EA based on X121 XCA and X3MA indicators" #property strict // Include Common Library #include "../Libraries/x-saherelm.common.lib.mq5" #include // Indicator handles int xcaHandle = INVALID_HANDLE; int x3maHandle = INVALID_HANDLE; // Indicator buffers for XCA double xcaTrendBuffer[]; double xcaTrendColorBuffer[]; double xcaKIBuffer[]; double xcaKIColorBuffer[]; double xcaVidyaBuffer[]; double xcaVidyaColorBuffer[]; double xcaSwingLowBuffer[]; double xcaSwingHighBuffer[]; double xcaSupportBuffer[]; double xcaResistanceBuffer[]; double xcaSLBuffer[]; // Short Cycle Low double xcaSHBuffer[]; // Short Cycle High double xcaMLBuffer[]; // Medium Cycle Low double xcaMHBuffer[]; // Medium Cycle High double xcaFiboLevel2Buffer[]; // 50% Fibo level // Indicator buffers for X3MA double x3maFastBuffer[]; double x3maFastColorBuffer[]; double x3maMediumBuffer[]; double x3maMediumColorBuffer[]; double x3maSlowBuffer[]; double x3maSlowColorBuffer[]; // Trade parameters input group "Trade Settings" input double LotSize = 0.1; // Fixed Lot Size input bool UseAutoLotSize = false; // Use Auto Lot Size input double RiskPercent = 1.0; // Risk Percent (for Auto Lot) input int StopLoss = 100; // Stop Loss in points input int TakeProfit = 200; // Take Profit in points input bool UseTrailingStop = true; // Use Trailing Stop input int TrailingStop = 50; // Trailing Stop in points input int TrailingStep = 10; // Trailing Step in points input group "Strategy Parameters" input bool UseSwingPoints = true; // Use Swing Points for Entry input bool UseFiboLevels = true; // Use Fibonacci Levels input bool UseMAAlignment = true; // Require All MAs Alignment input bool UseKIConfirmation = true; // Require KI Confirmation input bool UseVidyaConfirmation = true; // Require VIDYA Confirmation input bool UseTrendConfirmation = true; // Require Trend Confirmation input group "Money Management" input bool UseMultipleTargets = true; // Use Multiple Profit Targets input double Target1Percent = 33.0; // First Target Percentage input double Target2Percent = 33.0; // Second Target Percentage input double Target3Percent = 34.0; // Third Target Percentage input group "Time Filter" input bool UseTimeFilter = false; // Use Time Filter input string StartTradeTime = "08:00"; // Start Trading Time (Server Time) input string EndTradeTime = "16:00"; // End Trading Time (Server Time) // Global variables int magicNumber = 12121; bool isTradingAllowed = true; datetime lastBarTime = 0; int barsTotalPrev = 0; // Trade objects CTrade trade; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize trade object trade.SetExpertMagicNumber(magicNumber); // Initialize XCA indicator xcaHandle = iCustom(_Symbol, _Period, "x-saherelm.x121.xca"); if (xcaHandle == INVALID_HANDLE) { Print("Failed to create handle of the XCA indicator"); return (INIT_FAILED); } // Initialize X3MA indicator x3maHandle = iCustom(_Symbol, _Period, "x-saherelm.x121.x3ma"); if (x3maHandle == INVALID_HANDLE) { Print("Failed to create handle of the X3MA indicator"); return (INIT_FAILED); } // Set up arrays as series ArraySetAsSeries(xcaTrendBuffer, true); ArraySetAsSeries(xcaTrendColorBuffer, true); ArraySetAsSeries(xcaKIBuffer, true); ArraySetAsSeries(xcaKIColorBuffer, true); ArraySetAsSeries(xcaVidyaBuffer, true); ArraySetAsSeries(xcaVidyaColorBuffer, true); ArraySetAsSeries(xcaSwingLowBuffer, true); ArraySetAsSeries(xcaSwingHighBuffer, true); ArraySetAsSeries(xcaSupportBuffer, true); ArraySetAsSeries(xcaResistanceBuffer, true); ArraySetAsSeries(xcaSLBuffer, true); ArraySetAsSeries(xcaSHBuffer, true); ArraySetAsSeries(xcaMLBuffer, true); ArraySetAsSeries(xcaMHBuffer, true); ArraySetAsSeries(xcaFiboLevel2Buffer, true); ArraySetAsSeries(x3maFastBuffer, true); ArraySetAsSeries(x3maFastColorBuffer, true); ArraySetAsSeries(x3maMediumBuffer, true); ArraySetAsSeries(x3maMediumColorBuffer, true); ArraySetAsSeries(x3maSlowBuffer, true); ArraySetAsSeries(x3maSlowColorBuffer, true); return (INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Release indicator handles if (xcaHandle != INVALID_HANDLE) IndicatorRelease(xcaHandle); if (x3maHandle != INVALID_HANDLE) IndicatorRelease(x3maHandle); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Check if we're allowed to trade based on time filter if (UseTimeFilter && !IsTradeTimeAllowed()) return; // Get current bar time datetime currentBarTime = iTime(_Symbol, _Period, 0); // Only process on new bar if (currentBarTime == lastBarTime) return; lastBarTime = currentBarTime; // Update indicator buffers if (!UpdateIndicatorBuffers()) return; // Check for open positions and manage them ManageOpenPositions(); // Check for new trade signals CheckForTradeSignals(); } //+------------------------------------------------------------------+ //| Update all indicator buffers | //+------------------------------------------------------------------+ bool UpdateIndicatorBuffers() { // Copy XCA indicator buffers if (CopyBuffer(xcaHandle, 18, 0, 3, xcaTrendBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 19, 0, 3, xcaTrendColorBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 20, 0, 3, xcaKIBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 21, 0, 3, xcaKIColorBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 26, 0, 3, xcaVidyaBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 27, 0, 3, xcaVidyaColorBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 22, 0, 3, xcaSwingLowBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 23, 0, 3, xcaSwingHighBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 8, 0, 3, xcaSupportBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 9, 0, 3, xcaResistanceBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 0, 0, 3, xcaSHBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 1, 0, 3, xcaSLBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 2, 0, 3, xcaMHBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 3, 0, 3, xcaMLBuffer) < 3) return false; if (CopyBuffer(xcaHandle, 15, 0, 3, xcaFiboLevel2Buffer) < 3) return false; // Copy X3MA indicator buffers if (CopyBuffer(x3maHandle, 0, 0, 3, x3maFastBuffer) < 3) return false; if (CopyBuffer(x3maHandle, 1, 0, 3, x3maFastColorBuffer) < 3) return false; if (CopyBuffer(x3maHandle, 2, 0, 3, x3maMediumBuffer) < 3) return false; if (CopyBuffer(x3maHandle, 3, 0, 3, x3maMediumColorBuffer) < 3) return false; if (CopyBuffer(x3maHandle, 4, 0, 3, x3maSlowBuffer) < 3) return false; if (CopyBuffer(x3maHandle, 5, 0, 3, x3maSlowColorBuffer) < 3) return false; return true; } //+------------------------------------------------------------------+ //| Check if current time is within allowed trading hours | //+------------------------------------------------------------------+ bool IsTradeTimeAllowed() { // If time filter is not enabled, always allow trading if (!UseTimeFilter) return true; // Get current server time datetime serverTime = TimeCurrent(); MqlDateTime currentTime; TimeToStruct(serverTime, currentTime); // Convert start and end time strings to hours and minutes int startHour = 0, startMinute = 0; int endHour = 0, endMinute = 0; // Parse start time string startTimeParts[]; if (StringSplit(StartTradeTime, ':', startTimeParts) == 2) { startHour = (int)StringToInteger(startTimeParts[0]); startMinute = (int)StringToInteger(startTimeParts[1]); } // Parse end time string endTimeParts[]; if (StringSplit(EndTradeTime, ':', endTimeParts) == 2) { endHour = (int)StringToInteger(endTimeParts[0]); endMinute = (int)StringToInteger(endTimeParts[1]); } // Convert current time, start time and end time to minutes for easy comparison int currentTimeInMinutes = currentTime.hour * 60 + currentTime.min; int startTimeInMinutes = startHour * 60 + startMinute; int endTimeInMinutes = endHour * 60 + endMinute; // Check if current time is within trading hours bool isAllowed = false; // If end time is greater than start time (same day trading session) if (endTimeInMinutes > startTimeInMinutes) { isAllowed = (currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes <= endTimeInMinutes); } // If end time is less than start time (overnight trading session) else if (endTimeInMinutes < startTimeInMinutes) { isAllowed = (currentTimeInMinutes >= startTimeInMinutes || currentTimeInMinutes <= endTimeInMinutes); } // If start time equals end time (24-hour trading) else { isAllowed = true; } return isAllowed; } //+------------------------------------------------------------------+ //| Check for new trade signals | //+------------------------------------------------------------------+ void CheckForTradeSignals() { // Don't open new trades if we already have open positions if (CountOpenPositions() > 0) return; // Check for buy signal if (IsBuySignal()) { OpenBuyPosition(); } // Check for sell signal else if (IsSellSignal()) { OpenSellPosition(); } } //+------------------------------------------------------------------+ //| Check if we have a valid buy signal | //+------------------------------------------------------------------+ bool IsBuySignal() { // 1. Trend Confirmation bool trendConfirmation = true; if (UseTrendConfirmation) { // X3MA: Fast MA crosses above Medium MA bool fastCrossingAboveMedium = x3maFastBuffer[1] <= x3maMediumBuffer[1] && x3maFastBuffer[0] > x3maMediumBuffer[0]; // X3MA: All three MAs are in bullish alignment bool maAlignment = true; if (UseMAAlignment) { maAlignment = x3maFastBuffer[0] > x3maMediumBuffer[0] && x3maMediumBuffer[0] > x3maSlowBuffer[0]; } // XCA: VIDYA line shows bullish color bool vidyaBullish = true; if (UseVidyaConfirmation) { vidyaBullish = xcaVidyaColorBuffer[0] == 1; // 1 is bullish color index } // XCA: Trend line shows bullish color bool trendBullish = xcaTrendColorBuffer[0] == 1; // 1 is bullish color index trendConfirmation = (fastCrossingAboveMedium || maAlignment) && (vidyaBullish || !UseVidyaConfirmation) && trendBullish; } // 2. Cycle Analysis bool cycleAnalysis = true; { // XCA: Price is above the Short Cycle low double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); bool priceAboveSL = currentPrice > xcaSLBuffer[0]; // XCA: Medium Cycle is in uptrend phase bool mediumCycleUptrend = xcaMLBuffer[0] > xcaMLBuffer[1]; // XCA: Support level is established and holding bool supportHolding = currentPrice > xcaSupportBuffer[0]; cycleAnalysis = priceAboveSL && mediumCycleUptrend && supportHolding; } // 3. Entry Timing bool entryTiming = true; { // XCA: A swing low is identified bool swingLowFound = UseSwingPoints ? xcaSwingLowBuffer[0] != 0 : true; // XCA: Price is near but above the Fibonacci level 2 (50% retracement) bool nearFiboLevel = true; if (UseFiboLevels) { double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double fiboLevel = xcaFiboLevel2Buffer[0]; double priceDiff = MathAbs(currentPrice - fiboLevel); double priceRange = xcaResistanceBuffer[0] - xcaSupportBuffer[0]; nearFiboLevel = priceDiff < priceRange * 0.1 && currentPrice > fiboLevel; } // XCA: KI line shows bullish color bool kiBullish = true; if (UseKIConfirmation) { kiBullish = xcaKIColorBuffer[0] == 1; // 1 is bullish color index } entryTiming = swingLowFound && (nearFiboLevel || !UseFiboLevels) && (kiBullish || !UseKIConfirmation); } return trendConfirmation && cycleAnalysis && entryTiming; } //+------------------------------------------------------------------+ //| Check if we have a valid sell signal | //+------------------------------------------------------------------+ bool IsSellSignal() { // 1. Trend Confirmation bool trendConfirmation = true; if (UseTrendConfirmation) { // X3MA: Fast MA crosses below Medium MA bool fastCrossingBelowMedium = x3maFastBuffer[1] >= x3maMediumBuffer[1] && x3maFastBuffer[0] < x3maMediumBuffer[0]; // X3MA: All three MAs are in bearish alignment bool maAlignment = true; if (UseMAAlignment) { maAlignment = x3maFastBuffer[0] < x3maMediumBuffer[0] && x3maMediumBuffer[0] < x3maSlowBuffer[0]; } // XCA: VIDYA line shows bearish color bool vidyaBearish = true; if (UseVidyaConfirmation) { vidyaBearish = xcaVidyaColorBuffer[0] == 2; // 2 is bearish color index } // XCA: Trend line shows bearish color bool trendBearish = xcaTrendColorBuffer[0] == 2; // 2 is bearish color index trendConfirmation = (fastCrossingBelowMedium || maAlignment) && (vidyaBearish || !UseVidyaConfirmation) && trendBearish; } // 2. Cycle Analysis bool cycleAnalysis = true; { // XCA: Price is below the Short Cycle high double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); bool priceBelowSH = currentPrice < xcaSHBuffer[0]; // XCA: Medium Cycle is in downtrend phase bool mediumCycleDowntrend = xcaMHBuffer[0] < xcaMHBuffer[1]; // XCA: Resistance level is established and holding bool resistanceHolding = currentPrice < xcaResistanceBuffer[0]; cycleAnalysis = priceBelowSH && mediumCycleDowntrend && resistanceHolding; } // 3. Entry Timing bool entryTiming = true; { // XCA: A swing high is identified bool swingHighFound = UseSwingPoints ? xcaSwingHighBuffer[0] != 0 : true; // XCA: Price is near but below the Fibonacci level 2 (50% retracement) bool nearFiboLevel = true; if (UseFiboLevels) { double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double fiboLevel = xcaFiboLevel2Buffer[0]; double priceDiff = MathAbs(currentPrice - fiboLevel); double priceRange = xcaResistanceBuffer[0] - xcaSupportBuffer[0]; nearFiboLevel = priceDiff < priceRange * 0.1 && currentPrice < fiboLevel; } // XCA: KI line shows bearish color bool kiBearish = true; if (UseKIConfirmation) { kiBearish = xcaKIColorBuffer[0] == 2; // 2 is bearish color index } entryTiming = swingHighFound && (nearFiboLevel || !UseFiboLevels) && (kiBearish || !UseKIConfirmation); } return trendConfirmation && cycleAnalysis && entryTiming; } //+------------------------------------------------------------------+ //| Count open positions with our magic number | //+------------------------------------------------------------------+ int CountOpenPositions() { int count = 0; int total = PositionsTotal(); for (int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if (ticket <= 0) continue; // Check if position belongs to current symbol and our EA if (PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == magicNumber) { count++; } } return count; } //+------------------------------------------------------------------+ //| Manage open positions (trailing stops, partial closes) | //+------------------------------------------------------------------+ void ManageOpenPositions() { int total = PositionsTotal(); // Loop through all open positions for (int i = total - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if (ticket <= 0) continue; // Check if position belongs to current symbol and our EA if (PositionGetString(POSITION_SYMBOL) != _Symbol || PositionGetInteger(POSITION_MAGIC) != magicNumber) continue; // Get position details double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); double stopLoss = PositionGetDouble(POSITION_SL); double takeProfit = PositionGetDouble(POSITION_TP); double positionVolume = PositionGetDouble(POSITION_VOLUME); ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // Check for exit signals bool exitSignal = false; // For BUY positions if (positionType == POSITION_TYPE_BUY) { // Exit if Fast MA crosses below Medium MA if (x3maFastBuffer[1] > x3maMediumBuffer[1] && x3maFastBuffer[0] <= x3maMediumBuffer[0]) exitSignal = true; // Apply trailing stop if enabled if (UseTrailingStop && !exitSignal) { // Calculate new stop loss level double newStopLoss = 0; // Use the most recent swing low as trailing stop if available if (xcaSwingLowBuffer[0] > 0 && xcaSwingLowBuffer[0] < currentPrice) { newStopLoss = xcaSwingLowBuffer[0] - 5 * _Point; } else { // Traditional trailing stop double trailingLevel = currentPrice - TrailingStop * _Point; if (trailingLevel > stopLoss + TrailingStep * _Point) newStopLoss = trailingLevel; } // Update stop loss if we have a better level if (newStopLoss > stopLoss && newStopLoss > 0) { trade.PositionModify(ticket, newStopLoss, takeProfit); Print("Updated BUY trailing stop to: ", newStopLoss); } } // Handle multiple targets if (UseMultipleTargets && positionVolume > LotSize * 0.5) { // First target: When price reaches resistance or initial TP if (currentPrice >= xcaResistanceBuffer[0] && xcaResistanceBuffer[0] > openPrice) { double closeVolume = NormalizeDouble(positionVolume * Target1Percent / 100, 2); if (closeVolume > 0) { trade.PositionClosePartial(ticket, closeVolume); Print("First target reached for BUY position. Partially closed: ", closeVolume); } } // Second target: When price reaches Fibonacci level 3 (76.4%) double fiboLevel3Buffer[]; ArraySetAsSeries(fiboLevel3Buffer, true); if (CopyBuffer(xcaHandle, 16, 0, 1, fiboLevel3Buffer) > 0) { double fiboLevel3 = fiboLevel3Buffer[0]; if (fiboLevel3 > 0 && currentPrice >= fiboLevel3 && fiboLevel3 > openPrice) { double closeVolume = NormalizeDouble(positionVolume * Target2Percent / 100, 2); if (closeVolume > 0) { trade.PositionClosePartial(ticket, closeVolume); Print("Second target reached for BUY position. Partially closed: ", closeVolume); } } } } } // For SELL positions else if (positionType == POSITION_TYPE_SELL) { // Exit if Fast MA crosses above Medium MA if (x3maFastBuffer[1] < x3maMediumBuffer[1] && x3maFastBuffer[0] >= x3maMediumBuffer[0]) exitSignal = true; // Apply trailing stop if enabled if (UseTrailingStop && !exitSignal) { // Calculate new stop loss level double newStopLoss = 0; // Use the most recent swing high as trailing stop if available if (xcaSwingHighBuffer[0] > 0 && xcaSwingHighBuffer[0] > currentPrice) { newStopLoss = xcaSwingHighBuffer[0] + 5 * _Point; } else { // Traditional trailing stop double trailingLevel = currentPrice + TrailingStop * _Point; if (trailingLevel < stopLoss - TrailingStep * _Point || stopLoss == 0) newStopLoss = trailingLevel; } // Update stop loss if we have a better level if ((newStopLoss < stopLoss || stopLoss == 0) && newStopLoss > 0) { trade.PositionModify(ticket, newStopLoss, takeProfit); Print("Updated SELL trailing stop to: ", newStopLoss); } } // Handle multiple targets if (UseMultipleTargets && positionVolume > LotSize * 0.5) { // First target: When price reaches support or initial TP if (currentPrice <= xcaSupportBuffer[0] && xcaSupportBuffer[0] < openPrice) { double closeVolume = NormalizeDouble(positionVolume * Target1Percent / 100, 2); if (closeVolume > 0) { trade.PositionClosePartial(ticket, closeVolume); Print("First target reached for SELL position. Partially closed: ", closeVolume); } } // Second target: When price reaches Fibonacci level 3 (76.4%) double fiboLevel3Buffer[]; ArraySetAsSeries(fiboLevel3Buffer, true); if (CopyBuffer(xcaHandle, 16, 0, 1, fiboLevel3Buffer) > 0) { double fiboLevel3 = fiboLevel3Buffer[0]; if (fiboLevel3 > 0 && currentPrice <= fiboLevel3 && fiboLevel3 < openPrice) { double closeVolume = NormalizeDouble(positionVolume * Target2Percent / 100, 2); if (closeVolume > 0) { trade.PositionClosePartial(ticket, closeVolume); Print("Second target reached for SELL position. Partially closed: ", closeVolume); } } } } } // Close position if exit signal is triggered if (exitSignal) { trade.PositionClose(ticket); Print("Exit signal triggered. Position closed."); } } } //+------------------------------------------------------------------+ //| Open a buy position with proper risk management | //+------------------------------------------------------------------+ void OpenBuyPosition() { double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double stopLossPrice = 0; double takeProfitPrice = 0; // Calculate stop loss price if (StopLoss > 0) { // Use either the specified stop loss or the swing low, whichever is closer double swingLowPrice = xcaSwingLowBuffer[0]; double slByPoints = entryPrice - StopLoss * _Point; // If we have a valid swing low and it's not too far if (swingLowPrice > 0 && entryPrice - swingLowPrice < StopLoss * 2 * _Point) stopLossPrice = swingLowPrice - 5 * _Point; // Place SL slightly below swing low else stopLossPrice = slByPoints; } // Calculate take profit price if (TakeProfit > 0) { // If using multiple targets, we'll set the first one here and manage the rest in position management if (UseMultipleTargets) { // Use resistance level as first target if available if (xcaResistanceBuffer[0] > entryPrice) takeProfitPrice = xcaResistanceBuffer[0]; else takeProfitPrice = entryPrice + TakeProfit * _Point; } else { takeProfitPrice = entryPrice + TakeProfit * _Point; } } // Calculate position size double volume = LotSize; if (UseAutoLotSize && stopLossPrice > 0) { double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100; double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE) * (SymbolInfoDouble(_Symbol, SYMBOL_POINT) / SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE)); double pipDistance = MathAbs(entryPrice - stopLossPrice) / SymbolInfoDouble(_Symbol, SYMBOL_POINT); if (pipDistance > 0 && pipValue > 0) volume = NormalizeDouble(riskAmount / (pipDistance * pipValue), 2); // Ensure volume is within allowed limits double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); volume = MathMax(minVolume, MathMin(maxVolume, volume)); volume = NormalizeDouble(volume / volumeStep, 0) * volumeStep; } // Execute the trade trade.Buy(volume, _Symbol, 0, stopLossPrice, takeProfitPrice, "X121 Strategy Buy"); // Log the trade Print("BUY Signal: Opening position at ", entryPrice, ", SL: ", stopLossPrice, ", TP: ", takeProfitPrice, ", Volume: ", volume); } //+------------------------------------------------------------------+ //| Open a sell position with proper risk management | //+------------------------------------------------------------------+ void OpenSellPosition() { double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double stopLossPrice = 0; double takeProfitPrice = 0; // Calculate stop loss price if (StopLoss > 0) { // Use either the specified stop loss or the swing high, whichever is closer double swingHighPrice = xcaSwingHighBuffer[0]; double slByPoints = entryPrice + StopLoss * _Point; // If we have a valid swing high and it's not too far if (swingHighPrice > 0 && swingHighPrice - entryPrice < StopLoss * 2 * _Point) stopLossPrice = swingHighPrice + 5 * _Point; // Place SL slightly above swing high else stopLossPrice = slByPoints; } // Calculate take profit price if (TakeProfit > 0) { // If using multiple targets, we'll set the first one here and manage the rest in position management if (UseMultipleTargets) { // Use support level as first target if available if (xcaSupportBuffer[0] > 0 && xcaSupportBuffer[0] < entryPrice) takeProfitPrice = xcaSupportBuffer[0]; else takeProfitPrice = entryPrice - TakeProfit * _Point; } else { takeProfitPrice = entryPrice - TakeProfit * _Point; } } // Calculate position size double volume = LotSize; if (UseAutoLotSize && stopLossPrice > 0) { double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * RiskPercent / 100; double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE) * (SymbolInfoDouble(_Symbol, SYMBOL_POINT) / SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE)); double pipDistance = MathAbs(entryPrice - stopLossPrice) / SymbolInfoDouble(_Symbol, SYMBOL_POINT); if (pipDistance > 0 && pipValue > 0) volume = NormalizeDouble(riskAmount / (pipDistance * pipValue), 2); // Ensure volume is within allowed limits double minVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); volume = MathMax(minVolume, MathMin(maxVolume, volume)); volume = NormalizeDouble(volume / volumeStep, 0) * volumeStep; } // Execute the trade trade.Sell(volume, _Symbol, 0, stopLossPrice, takeProfitPrice, "X121 Strategy Sell"); // Log the trade Print("SELL Signal: Opening position at ", entryPrice, ", SL: ", stopLossPrice, ", TP: ", takeProfitPrice, ", Volume: ", volume); }