//+------------------------------------------------------------------+ //| EnhancedEA.mq5 //| Enhanced with Harmonic Patterns and Pivot Points (No Fibonacci) //+------------------------------------------------------------------+ #property strict #include CTrade trade; //--- Trading Parameters // Removed fixed lot size input in favor of risk-based volume calculation // input double LotSize = 0.1; // (Removed) //--- Risk management: risk per trade as a percentage of account equity // Note: A value of 0.01 means 0.01% of the equity. input double RiskPerTrade = 0.5; input int StopLossPips = 150; // Stop loss in pips input int TakeProfitPips = 300; // Take profit in pips input int Slippage = 10; // Allowed slippage in points //--- Input parameters for Moving Averages input int FastMAPeriod = 10; // Fast Moving Average period input int SlowMAPeriod = 20; // Slow Moving Average period //--- Input parameters for Pivot Points input bool UsePivotPoints = true; // Enable/Disable Pivot Points //--- Input parameters for Harmonic Patterns input bool UseHarmonicPatterns = true; // Enable/Disable Harmonic Patterns input int SwingLookback = 100; // Bars for swing detection input double PatternTolerance = 0.05; // Allowed ratio variance //--- Input parameters for Trailing Stop input int TrailingStart = 50; // Profit in points to start trailing input int TrailingDistance = 30; // Distance to maintain from current price input int TrailingStep = 10; // Step in points to move the stop loss input double StopLossFactor = 1.0; // Multiplier for (R2 - R1) or (S1 - S2) input double TakeProfitFactor = 1.0; // Multiplier for take-profit // (RiskPerTrade already declared above) input long MagicNumber = 98765; // Magic number for this EA /***** Day-of-Week Logic *****/ input bool TradeMonday = true; input bool TradeTuesday = true; input bool TradeWednesday = true; input bool TradeThursday = true; input bool TradeFriday = true; input bool TradeSaturday = false; input bool TradeSunday = false; /************** RSI Tuning ****************/ input int RSIOversold = 40; //RSI over bought input int RSIOverbought = 60; //RSI over sold //--- Pin Bar Filter input bool UsePinBarFilter = true; //--- Control for Previous Day Trade Restriction input bool RequirePreviousDayTrade = true; //--- Global variables (Pivot Points) static datetime TradeDate = 0; // Tracks the current day static bool OrdersPlaced = false; double PivotPoint, S1, S2, R1, R2; // Pivot Points and support/resistance // Define ENUM_SWING_TYPE enum ENUM_SWING_TYPE { SWING_MODE_LOW = 0, // Start with low swing points SWING_MODE_HIGH = 1 // Start with high swing points }; /***** For multiple-trade trailing: track best price per position ticket *****/ /** We'll keep two parallel static arrays: - posTicketArray[] holds position tickets - bestPriceArray[] holds the best price so far for that ticket (highest for BUY, lowest for SELL). We only store up to some arbitrary max positions (e.g. 100). Each time we see a new position, we add if not found. Each time a position is closed, we remove it from the arrays. */ #define MAX_POSITIONS 100 static ulong posTicketArray[MAX_POSITIONS]; static double bestPriceArray[MAX_POSITIONS]; static int posCount = 0; // How many valid entries we have bool IsTradingDay(); //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("Expert Advisor initialized (no Fibonacci)."); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("Expert Advisor deinitialized."); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Calculate Moving Averages (MQL5 style) double FastMA = iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE); double SlowMA = iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE); //--- Calculate Pivot Points if(UsePivotPoints) CalculatePivotPoints(); //--- Detect Harmonic Patterns bool bullishSignal = false, bearishSignal = false; if(UseHarmonicPatterns) { bullishSignal = DetectBullishPatterns(); bearishSignal = DetectBearishPatterns(); } //--- Get current market prices double currentClose = iClose(_Symbol, PERIOD_CURRENT, 0); MqlTick lastTick; SymbolInfoTick(_Symbol, lastTick); // Check for new D1 bar datetime today = iTime(_Symbol, PERIOD_D1, 0); if(today != TradeDate) { TradeDate = today; OrdersPlaced = false; CleanUpClosedPositions(); } //--- Execute trading logic ExecuteTradingLogic(FastMA, SlowMA, currentClose, lastTick, bullishSignal, bearishSignal); ApplyTrailingStop(); } //+------------------------------------------------------------------+ //| Calculate Pivot Points | //+------------------------------------------------------------------+ void CalculatePivotPoints() { MqlRates daily[]; // Copy exactly 1 bar from the previous D1 candle if(CopyRates(_Symbol, PERIOD_D1, 1, 1, daily) < 1) { Print("Failed to copy daily rates for pivot calculation."); return; } PivotPoint = (daily[0].high + daily[0].low + daily[0].close) / 3.0; S1 = (2.0 * PivotPoint) - daily[0].high; R1 = (2.0 * PivotPoint) - daily[0].low; S2 = PivotPoint - (daily[0].high - daily[0].low); R2 = PivotPoint + (daily[0].high - daily[0].low); } //+------------------------------------------------------------------+ //| Harmonic Pattern Detection System | //+------------------------------------------------------------------+ bool DetectBullishPatterns() { double X, A, B, C, D; if(!GetRecentSwings(X, A, B, C, D, SWING_MODE_LOW)) return false; return CheckGartley(X, A, B, C, D, true) || CheckButterfly(X, A, B, C, D, true) || CheckBat(X, A, B, C, D, true); } bool DetectBearishPatterns() { double X, A, B, C, D; if(!GetRecentSwings(X, A, B, C, D, SWING_MODE_HIGH)) return false; return CheckGartley(X, A, B, C, D, false) || CheckButterfly(X, A, B, C, D, false) || CheckBat(X, A, B, C, D, false); } //+------------------------------------------------------------------+ //| Swing Point Detection | //+------------------------------------------------------------------+ bool GetRecentSwings(double &X, double &A, double &B, double &C, double &D, ENUM_SWING_TYPE startType) { int swings[5]; int direction = (int)startType; // Initialize direction based on startType for(int i = 0; i < 5; i++) { int swingIndex = -1; if(direction == SWING_MODE_HIGH) swingIndex = iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, SwingLookback, 0); else swingIndex = iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, SwingLookback, 0); if(swingIndex == -1) return false; swings[i] = swingIndex; direction = (direction == SWING_MODE_HIGH) ? SWING_MODE_LOW : SWING_MODE_HIGH; } X = (startType == SWING_MODE_LOW) ? iLow(_Symbol, PERIOD_CURRENT, swings[0]) : iHigh(_Symbol, PERIOD_CURRENT, swings[0]); A = (startType == SWING_MODE_LOW) ? iHigh(_Symbol, PERIOD_CURRENT, swings[1]) : iLow(_Symbol, PERIOD_CURRENT, swings[1]); B = (startType == SWING_MODE_LOW) ? iLow(_Symbol, PERIOD_CURRENT, swings[2]) : iHigh(_Symbol, PERIOD_CURRENT, swings[2]); C = (startType == SWING_MODE_LOW) ? iHigh(_Symbol, PERIOD_CURRENT, swings[3]) : iLow(_Symbol, PERIOD_CURRENT, swings[3]); D = (startType == SWING_MODE_LOW) ? iLow(_Symbol, PERIOD_CURRENT, swings[4]) : iHigh(_Symbol, PERIOD_CURRENT, swings[4]); return true; } //+------------------------------------------------------------------+ //| Pattern Validation Functions | //+------------------------------------------------------------------+ bool CheckGartley(double X, double A, double B, double C, double D, bool bullish) { double XA = MathAbs(A - X); double AB = MathAbs(B - A); double BC = MathAbs(C - B); double CD = MathAbs(D - C); bool validAB = CheckRatio(AB/XA, 0.618); bool validBC = CheckRatio(BC/AB, 0.382) || CheckRatio(BC/AB, 0.886); bool validCD = CheckRatio(CD/BC, 1.272) || CheckRatio(CD/BC, 1.618); if(bullish) return (validAB && validBC && validCD && D > X); return (validAB && validBC && validCD && D < X); } bool CheckButterfly(double X, double A, double B, double C, double D, bool bullish) { double XA = MathAbs(A - X); double AB = MathAbs(B - A); double BC = MathAbs(C - B); double CD = MathAbs(D - C); bool validAB = CheckRatio(AB/XA, 0.786); bool validBC = CheckRatio(BC/AB, 0.382) || CheckRatio(BC/AB, 0.886); bool validCD = CheckRatio(CD/BC, 1.618) || CheckRatio(CD/BC, 2.24); if(bullish) return (validAB && validBC && validCD && D > X); return (validAB && validBC && validCD && D < X); } bool CheckBat(double X, double A, double B, double C, double D, bool bullish) { double XA = MathAbs(A - X); double AB = MathAbs(B - A); double BC = MathAbs(C - B); double CD = MathAbs(D - C); bool validAB = CheckRatio(AB/XA, 0.382) || CheckRatio(AB/XA, 0.5); bool validBC = CheckRatio(BC/AB, 0.382) || CheckRatio(BC/AB, 0.886); bool validCD = CheckRatio(CD/BC, 1.618) || CheckRatio(CD/BC, 2.618); bool validXD = CheckRatio(MathAbs(D - X)/XA, 0.886); if(bullish) return (validAB && validBC && validCD && validXD && D > X ); return (validAB && validBC && validCD && validXD && D < X); } //+------------------------------------------------------------------+ //| Ratio Validation Helper | //+------------------------------------------------------------------+ bool CheckRatio(double ratio, double target) { return (ratio >= target*(1 - PatternTolerance) && ratio <= target*(1 + PatternTolerance)); } //+------------------------------------------------------------------+ //| Calculate RSI | //+------------------------------------------------------------------+ bool IsRSIOversold() { int RSIPeriod = 14; double rsi[]; if(CopyBuffer(iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE), 0, 0, 1, rsi) <= 0) { Print("Failed to retrieve RSI values"); return false; } return rsi[0] < RSIOversold; } bool IsRSIOverbought() { int RSIPeriod = 14; double rsi[]; if(CopyBuffer(iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE), 0, 0, 1, rsi) <= 0) { Print("Failed to retrieve RSI values"); return false; } return rsi[0] > RSIOverbought; } //+------------------------------------------------------------------+ //| Calculate ATR-based stop-loss | //+------------------------------------------------------------------+ double CalculateATRStopLoss() { int ATRPeriod = 14; double atrValue; int atrHandle = iATR(_Symbol, PERIOD_CURRENT, ATRPeriod); double atrThreshold = 0.0100; // Set based on historical analysis if (atrHandle == INVALID_HANDLE) { Print("Failed to create ATR handle"); return 0; } double atrBuffer[]; if (CopyBuffer(atrHandle, 0, 0, 1, atrBuffer) <= 0) { Print("Failed to retrieve ATR values"); return 0; } if (atrValue > atrThreshold) { Print("Skip trading volatility is too high"); return 0; // Skip trading if volatility is too high } atrValue = atrBuffer[0]; IndicatorRelease(atrHandle); return MathMax(atrValue * 2, SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 10); } //+------------------------------------------------------------------+ //| Ensure Stop Loss and Take Profit meet broker constraints | //+------------------------------------------------------------------+ void ValidateStopLevels(double &stopLoss, double &takeProfit, double entryPrice, ENUM_ORDER_TYPE orderType) { double minStopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * SymbolInfoDouble(_Symbol, SYMBOL_POINT); if (minStopLevel == 0) minStopLevel = SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 10; // Default fallback if (orderType == ORDER_TYPE_BUY) { if (stopLoss > 0 && (entryPrice - stopLoss) < minStopLevel) stopLoss = entryPrice - minStopLevel; if (takeProfit > 0 && (takeProfit - entryPrice) < minStopLevel) takeProfit = entryPrice + minStopLevel; } else if (orderType == ORDER_TYPE_SELL) { if (stopLoss > 0 && (stopLoss - entryPrice) < minStopLevel) stopLoss = entryPrice + minStopLevel; if (takeProfit > 0 && (entryPrice - takeProfit) < minStopLevel) takeProfit = entryPrice - minStopLevel; } // Ensure stopLoss and takeProfit are not equal to entryPrice if (stopLoss == entryPrice) stopLoss += minStopLevel; if (takeProfit == entryPrice) takeProfit -= minStopLevel; } //+------------------------------------------------------------------+ //| Enhanced Trading Logic with ATR Stop-Loss, RSI Filter, and Stop Validation | //+------------------------------------------------------------------+ void ExecuteTradingLogic(double fastMA, double slowMA, double closePrice, MqlTick &tick, bool bullishPattern, bool bearishPattern) { static datetime lastBar = 0; datetime currentBar = iTime(_Symbol, PERIOD_CURRENT, 0); // Only check on new bar formation if(lastBar == currentBar) return; lastBar = currentBar; bool pivotCondition = UsePivotPoints ? (closePrice > PivotPoint) : true; bool pivotBearCondition= UsePivotPoints ? (closePrice < PivotPoint) : true; bool bullishHarmonicCondition = UseHarmonicPatterns ? bullishPattern : true; bool bearishHarmonicCondition = UseHarmonicPatterns ? bearishPattern : true; //bool rsiBuyCondition = IsRSIOversold(); //bool rsiSellCondition = IsRSIOverbought(); double stopLoss = StopLossPips; double takeProfit = TakeProfitPips; //closePrice + (TakeProfitPips * SymbolInfoDouble(_Symbol, SYMBOL_POINT)); // Get candle data double openPrice = iOpen(_Symbol, PERIOD_CURRENT, 1); double pclosePrice = iClose(_Symbol, PERIOD_CURRENT, 1); double highPrice = iHigh(_Symbol, PERIOD_CURRENT, 1); double lowPrice = iLow(_Symbol, PERIOD_CURRENT, 1); bool isPinedBar = IsPinBar(openPrice, pclosePrice,highPrice, lowPrice); bool isBearishPinBar = IsBearishPinBar(openPrice, pclosePrice,highPrice, lowPrice); bool isBullishPinBar = IsBullishPinBar(openPrice, pclosePrice,highPrice, lowPrice); bool isDoji = IsDoji(openPrice, pclosePrice,highPrice, lowPrice); bool isStrongBullishCandle = IsStrongBullishCandle(openPrice, pclosePrice,highPrice, lowPrice); bool isStrongBearishCandle = IsStrongBearishCandle(openPrice, pclosePrice,highPrice, lowPrice); bool maBuyCondition = (fastMA > slowMA) && (PositionSelect(_Symbol) == false); if( maBuyCondition && ( isStrongBullishCandle) && !IsRSIOverbought() && (!RequirePreviousDayTrade || !IsTradeOpenForSymbol() || IsPreviousDayTradeOpen())) { double lot = CalculateLotSizeFromRisk(closePrice, closePrice - stopLoss); ValidateStopLevels(stopLoss, takeProfit, closePrice, ORDER_TYPE_BUY); ExecuteBuyOrder(lot, closePrice, stopLoss, takeProfit, Slippage); } bool maSellCondition = (fastMA < slowMA) && (PositionSelect(_Symbol) == false); if( maSellCondition && ( isStrongBearishCandle) && !IsRSIOversold() && (!RequirePreviousDayTrade || !IsTradeOpenForSymbol() || IsPreviousDayTradeOpen())) { double lot = CalculateLotSizeFromRisk(closePrice, closePrice + stopLoss); ValidateStopLevels(stopLoss, takeProfit, closePrice, ORDER_TYPE_SELL); ExecuteSellOrder(lot, closePrice, stopLoss, takeProfit, Slippage); } } //+------------------------------------------------------------------+ //| Check if an open trade is from the previous day | //+------------------------------------------------------------------+ bool IsPreviousDayTradeOpen() { datetime currentTime = TimeCurrent(); MqlDateTime nowStruct; TimeToStruct(currentTime, nowStruct); for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == _Symbol) { datetime openTime = PositionGetInteger(POSITION_TIME); MqlDateTime openStruct; TimeToStruct(openTime, openStruct); if(openStruct.day != nowStruct.day) return true; } } return false; } //+------------------------------------------------------------------+ //| Check if there are any open trades for the current symbol | //+------------------------------------------------------------------+ bool IsTradeOpenForSymbol() { for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == _Symbol) return true; } return false; } //+------------------------------------------------------------------+ //| Candle Pattern Detection | //+------------------------------------------------------------------+ bool IsBullishPinBar(double open, double close, double high, double low) { double body = MathAbs(open - close); double lowerWick = MathMin(open, close) - low; return (lowerWick > body * 2) && body < (high - low) * 0.3; } bool IsBearishPinBar(double open, double close, double high, double low) { double body = MathAbs(open - close); double upperWick = high - MathMax(open, close); return (upperWick > body * 2) && body < (high - low) * 0.3; } bool IsDoji(double open, double close, double high, double low) { double body = MathAbs(open - close); return (body < (high - low) * 0.1); } bool IsStrongBullishCandle(double open, double close, double high, double low) { double body = MathAbs(open - close); return (close > open && body > (high - low) * 0.6); } bool IsStrongBearishCandle(double open, double close, double high, double low) { double body = MathAbs(open - close); return (open > close && body > (high - low) * 0.6); } bool IsPinBar(double open, double close, double high, double low) { double body = MathAbs(open - close); double upperWick = high - MathMax(open, close); double lowerWick = MathMin(open, close) - low; return (upperWick > body * 2 || lowerWick > body * 2) && body < (high - low) * 0.3; } double GetVolumeProfileLevel(ENUM_TIMEFRAMES timeframe, int lookbackPeriod) { // Calculate the start time for the lookback period datetime start_time = TimeCurrent() - lookbackPeriod * PeriodSeconds(timeframe); double total_volume = 0; // Total volume over the lookback period double price_level = 0; // Weighted sum of price levels for(int i = 0; i < lookbackPeriod; i++) { // Get the volume and closing price for the current bar double bar_volume = iVolume(_Symbol, timeframe, i); double bar_price = iClose(_Symbol, timeframe, i); // Add to the total volume and weighted price level total_volume += bar_volume; price_level += bar_volume * bar_price; } // Avoid division by zero if(total_volume == 0) { Print("Error: Total volume is zero. Cannot calculate Point of Control (POC)."); return 0; // Return 0 or handle the error as needed } // Calculate and return the Point of Control (POC) return price_level / total_volume; } //--- Input parameters for ADX input int ADXPeriod = 14; // Period for ADX calculation // Function to calculate ADX double GetADX(ENUM_TIMEFRAMES timeframe) { int adx_handle = iADX(_Symbol, timeframe, ADXPeriod); if(adx_handle == INVALID_HANDLE) { Print("Error creating ADX handle: ", GetLastError()); return 0; } double adx_value[1]; // Array to store the ADX value if(CopyBuffer(adx_handle, 0, 0, 1, adx_value) <= 0) // Copy the main ADX line { Print("Error copying ADX buffer: ", GetLastError()); return 0; } return adx_value[0]; // Return the latest ADX value } double CalculateDynamicTakeProfit(double atrValue, double multiplier) { return atrValue * multiplier * SymbolInfoDouble(_Symbol, SYMBOL_POINT); } //+------------------------------------------------------------------+ //| Calculate lot size based on risk from entry to stop-loss | //+------------------------------------------------------------------+ double CalculateLotSizeFromRisk(double entryPrice, double stopLoss) { // Calculate the risk money (a percentage of account equity) double riskMoney = AccountInfoDouble(ACCOUNT_EQUITY) * (RiskPerTrade / 100.0); // Calculate the risk in points (using the symbol’s point size) double riskPoints = MathAbs(entryPrice - stopLoss) / SymbolInfoDouble(_Symbol, SYMBOL_POINT); // Obtain tick value and tick size to determine pip value per lot. double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); // Here we assume one pip equals one Symbol POINT in value terms. double pipValue = (tickValue / tickSize) * SymbolInfoDouble(_Symbol, SYMBOL_POINT); // Calculate volume so that: riskMoney = lot * (riskPoints * pipValue) double lot = riskMoney / (riskPoints * pipValue); return NormalizeDouble(lot, 2); } //+------------------------------------------------------------------+ //| Order Execution Helpers | //+------------------------------------------------------------------+ void ExecuteBuyOrder(double volume, double entryPrice, double stopLoss, double takeProfit, double slippage) { MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); // Set up the trade request request.action = TRADE_ACTION_DEAL; // Immediate order execution request.symbol = _Symbol; // Current symbol request.volume = volume; // Calculated volume based on risk request.type = ORDER_TYPE_BUY; // Buy order request.price = entryPrice; // Entry price request.sl = stopLoss; // Stop loss request.tp = takeProfit; // Take profit request.deviation = (uint)slippage; // Allowed slippage request.magic = MagicNumber; // Use the magic number // Send the order if(!OrderSend(request, result)) Print("Buy Order Failed: ", GetLastError()); else Print("Buy Order Executed Successfully"); } void ExecuteSellOrder(double volume, double entryPrice, double stopLoss, double takeProfit, double slippage) { MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); // Set up the trade request request.action = TRADE_ACTION_DEAL; // Immediate order execution request.symbol = _Symbol; // Current symbol request.volume = volume; // Calculated volume based on risk request.type = ORDER_TYPE_SELL; // Sell order request.price = entryPrice; // Entry price request.sl = stopLoss; // Stop loss request.tp = takeProfit; // Take profit request.deviation = (uint)slippage; // Allowed slippage request.magic = MagicNumber; // Magic number // Send the order if(!OrderSend(request, result)) Print("Sell Order Failed: ", GetLastError()); else Print("Sell Order Executed Successfully"); } //+------------------------------------------------------------------+ //| Apply trailing stop to open positions | //+------------------------------------------------------------------+ void ApplyTrailingStop() { double bidPrice, askPrice; MqlTick lastTick; if(SymbolInfoTick(_Symbol, lastTick)) { bidPrice = lastTick.bid; askPrice = lastTick.ask; } for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == _Symbol) { double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double stopLoss = PositionGetDouble(POSITION_SL); double takeProfit = PositionGetDouble(POSITION_TP); double currentPrice= (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? bidPrice : askPrice; double profitPoints= (currentPrice - openPrice) / SymbolInfoDouble(_Symbol, SYMBOL_POINT); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) profitPoints = -profitPoints; if(profitPoints >= TrailingStart) { double newStopLoss = currentPrice - TrailingDistance * SymbolInfoDouble(_Symbol, SYMBOL_POINT); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) newStopLoss = currentPrice + TrailingDistance * SymbolInfoDouble(_Symbol, SYMBOL_POINT); if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && newStopLoss > stopLoss + TrailingStep * SymbolInfoDouble(_Symbol, SYMBOL_POINT)) || (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && newStopLoss < stopLoss - TrailingStep * SymbolInfoDouble(_Symbol, SYMBOL_POINT))) { trade.PositionModify(PositionGetInteger(POSITION_TICKET), newStopLoss, takeProfit); } } } } } //+------------------------------------------------------------------+ //| Place Fade Orders if aligned with MA | //+------------------------------------------------------------------+ void PlaceFadeOrders() { double entryPriceSell = R2; double entryPriceBuy = S2; double slSell = R2 + ((R2 - R1) * StopLossFactor); double slBuy = S2 - ((S1 - S2) * StopLossFactor); double tpSell = (R1 * TakeProfitFactor); double tpBuy = (S1 * TakeProfitFactor); // For fade orders, calculate volume based on the risk between entry and stop loss. if(FastMAPeriod > SlowMAPeriod && entryPriceSell > PivotPoint) { double lotSell = CalculateLotSizeFromRisk(entryPriceSell, slSell); PlaceLimitOrder(ORDER_TYPE_SELL_LIMIT, entryPriceSell, slSell, tpSell, lotSell); } if(FastMAPeriod < SlowMAPeriod && entryPriceBuy < PivotPoint) { double lotBuy = CalculateLotSizeFromRisk(entryPriceBuy, slBuy); PlaceLimitOrder(ORDER_TYPE_BUY_LIMIT, entryPriceBuy, slBuy, tpBuy, lotBuy); } } //+------------------------------------------------------------------+ //| Place Limit Order Helper | //+------------------------------------------------------------------+ void PlaceLimitOrder(ENUM_ORDER_TYPE orderType, double entryPrice, double slPrice, double tpPrice, double volume) { MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); request.action = TRADE_ACTION_PENDING; request.symbol = _Symbol; request.magic = MagicNumber; request.volume = volume; request.type = orderType; request.price = entryPrice; request.sl = slPrice; request.tp = tpPrice; if(!OrderSend(request, result)) { Print("OrderSend failed: ", GetLastError()); } } //+------------------------------------------------------------------+ /*****===================================================================== * Cleanup any closed positions from the best price array *======================================================================*****/ void CleanUpClosedPositions() { // Loop through our array of known tickets and remove closed ones for(int i = posCount - 1; i >= 0; i--) { ulong storedTicket = posTicketArray[i]; bool found = false; uint totalPos = PositionsTotal(); for(uint p = 0; p < totalPos; p++) { if(PositionGetTicket(p) == storedTicket) { found = true; break; } } if(!found) { for(int j = i; j < posCount - 1; j++) { posTicketArray[j] = posTicketArray[j+1]; bestPriceArray[j] = bestPriceArray[j+1]; } posCount--; } } } /*****===================================================================== * IsTradingDay() *======================================================================*****/ bool IsTradingDay() { MqlDateTime mt; TimeToStruct(TimeCurrent(), mt); int dow = mt.day_of_week; // 0=Sun,1=Mon,...,6=Sat switch(dow) { case 0: return TradeSunday; case 1: return TradeMonday; case 2: return TradeTuesday; case 3: return TradeWednesday; case 4: return TradeThursday; case 5: return TradeFriday; case 6: return TradeSaturday; } return false; } //+------------------------------------------------------------------+