//+------------------------------------------------------------------+ //| COMPLETE REVERSAL BOT - 127.8% + 61.8% STRATEGY | //| Multi-Timeframe: 15M Setup | 5M Precision | 1H Trend Filter | //| Indicators: Stoch RSI + CCI Dual Divergence | //+------------------------------------------------------------------+ #property strict // === INPUT PARAMETERS === input double FirstEntryLots = 0.03; // 127.8% entry size input double SecondEntryLots = 0.02; // 61.8% add-on size input int SLPips = 10; // Base SL in pips input double MaxSpread = 3.0; // Max spread filter input int MomentumThreshold = 70; // Min momentum score input double Fib1278 = 1.278; // First entry fib level input double Fib618 = 0.618; // Second entry fib level enum EntryStyle { STYLE_AGGRESSIVE, // Enter on touch/wick STYLE_CONSERVATIVE // Enter on close confirmation }; input EntryStyle EntryMode = STYLE_CONSERVATIVE; enum TradePhase { PHASE_NONE, PHASE_1278_LONG, PHASE_618_ADDON }; // === GLOBAL VARIABLES === TradePhase currentPhase = PHASE_NONE; struct SetupData { double swingHigh; double swingLow; double fib1278Level; double entry1278Price; double newSwingHigh; double pullbackLow; bool swingEstablished; }; SetupData activeSetup; datetime last5MBar = 0; //+------------------------------------------------------------------+ //| EXPERT INITIALIZATION | //+------------------------------------------------------------------+ int OnInit() { if(StringFind(Symbol(), "Volatility") == -1) { Alert("This EA is designed for Synthetic Indices!"); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| MAIN TICK FUNCTION | //+------------------------------------------------------------------+ void OnTick() { // Spread filter if(SymbolInfoInteger(Symbol(), SYMBOL_SPREAD) > MaxSpread * 10) return; // Time filter MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); if(dt.min < 5 || dt.min > 55) return; // Check for new 5M bar datetime current5MBar = iTime(Symbol(), PERIOD_M5, 0); if(current5MBar != last5MBar) { last5MBar = current5MBar; // Entry logic if(PositionsTotal() == 0 || !HasOpenPosition("1278")) { switch(currentPhase) { case PHASE_NONE: Check1278LongEntry(); break; case PHASE_1278_LONG: CheckForPullbackSetup(); break; case PHASE_618_ADDON: Check618AddonEntry(); break; } } } // Manage positions if(PositionsTotal() > 0) ManagePositions(); } //+------------------------------------------------------------------+ //| 127.8% LONG ENTRY | //+------------------------------------------------------------------+ void Check1278LongEntry() { // 15M Setup int highestBar15M = iHighest(Symbol(), PERIOD_M15, MODE_HIGH, 30, 1); int lowestBar15M = iLowest(Symbol(), PERIOD_M15, MODE_LOW, 30, 1); activeSetup.swingHigh = iHigh(Symbol(), PERIOD_M15, highestBar15M); activeSetup.swingLow = iLow(Symbol(), PERIOD_M15, lowestBar15M); double range15M = activeSetup.swingHigh - activeSetup.swingLow; activeSetup.fib1278Level = activeSetup.swingHigh - (range15M * Fib1278); double low15M_0 = iLow(Symbol(), PERIOD_M15, 0); double tolerance15M = 5 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; if(!(low15M_0 <= activeSetup.fib1278Level + tolerance15M)) return; // 1H Trend filter if(GetTrendDirection(PERIOD_H1) == -1) return; // Divergence check if(!BullishDivergenceOnTimeframe(PERIOD_M15)) return; // Momentum score if(CalculateMomentumScore() < MomentumThreshold) return; // 5M Precision entry if(Check5MPrecisionEntry()) { Print("127.8% entry executed!"); } } //+------------------------------------------------------------------+ //| 5M PRECISION ENTRY WITH STYLE SWITCH | //+------------------------------------------------------------------+ bool Check5MPrecisionEntry() { double low5M_0 = iLow(Symbol(), PERIOD_M5, 0); double low5M_1 = iLow(Symbol(), PERIOD_M5, 1); double close5M_0 = iClose(Symbol(), PERIOD_M5, 0); double close5M_1 = iClose(Symbol(), PERIOD_M5, 1); double open5M_0 = iOpen(Symbol(), PERIOD_M5, 0); double high5M_0 = iHigh(Symbol(), PERIOD_M5, 0); double high5M_1 = iHigh(Symbol(), PERIOD_M5, 1); double tolerance5M = 3 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; if(!(low5M_0 <= activeSetup.fib1278Level + tolerance5M || low5M_1 <= activeSetup.fib1278Level + tolerance5M)) return false; // AGGRESSIVE MODE if(EntryMode == STYLE_AGGRESSIVE) { bool quickBounce = (low5M_0 <= activeSetup.fib1278Level + tolerance5M && close5M_0 > open5M_0); bool longWick = ((MathMin(close5M_0, open5M_0) - low5M_0) > MathAbs(close5M_0 - open5M_0) * 1.5); double stochMain[]; ArraySetAsSeries(stochMain, true); int stochHandle = iStochastic(Symbol(), PERIOD_M5, 14, 3, 3, MODE_SMA, STO_LOWHIGH); CopyBuffer(stochHandle, 0, 0, 2, stochMain); bool stochTurning = (stochMain[0] > stochMain[1] && stochMain[1] < 30); int aggSignals = (quickBounce ? 1 : 0) + (longWick ? 1 : 0) + (stochTurning ? 1 : 0); if(aggSignals >= 2) return Execute5MEntry("1278_5M_Aggressive", 8); } // CONSERVATIVE MODE else { bool bullishClose = (close5M_0 > open5M_0); bool abovePrevious = (close5M_0 > high5M_1); double microResistance = iHigh(Symbol(), PERIOD_M5, iHighest(Symbol(), PERIOD_M5, MODE_HIGH, 3, 1)); bool brokeResistance = (close5M_0 > microResistance); double stochMain[], stochSignal[]; ArraySetAsSeries(stochMain, true); ArraySetAsSeries(stochSignal, true); int stochHandle = iStochastic(Symbol(), PERIOD_M5, 14, 3, 3, MODE_SMA, STO_LOWHIGH); CopyBuffer(stochHandle, 0, 0, 2, stochMain); CopyBuffer(stochHandle, 1, 0, 2, stochSignal); bool stochCross = (stochMain[0] > stochSignal[0] && stochMain[1] <= stochSignal[1]); double cci[]; ArraySetAsSeries(cci, true); int cciHandle = iCCI(Symbol(), PERIOD_M5, 20, PRICE_TYPICAL); CopyBuffer(cciHandle, 0, 0, 2, cci); bool cciCross = (cci[0] > cci[1] && cci[1] < -100); int confSignals = (bullishClose ? 1 : 0) + (abovePrevious ? 1 : 0) + (brokeResistance ? 1 : 0) + (stochCross ? 1 : 0) + (cciCross ? 1 : 0); if(confSignals >= 3) return Execute5MEntry("1278_5M_Conservative", 6); } return false; } //+------------------------------------------------------------------+ //| EXECUTE 5M ENTRY | //+------------------------------------------------------------------+ bool Execute5MEntry(string comment, int slPips) { double entryPrice = SymbolInfoDouble(Symbol(), SYMBOL_ASK); double sl = NormalizeDouble(entryPrice - slPips * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10, _Digits); double tp = NormalizeDouble(activeSetup.swingHigh, _Digits); double lots = (EntryMode == STYLE_AGGRESSIVE) ? FirstEntryLots * 0.9 : FirstEntryLots; if(ExecuteTrade(ORDER_TYPE_BUY, lots, sl, tp, comment)) { currentPhase = PHASE_1278_LONG; activeSetup.entry1278Price = entryPrice; activeSetup.swingEstablished = false; return true; } return false; } //+------------------------------------------------------------------+ //| CHECK FOR PULLBACK SETUP (AFTER 127.8% MOVES UP) | //+------------------------------------------------------------------+ void CheckForPullbackSetup() { if(!HasOpenPosition("1278")) { ResetToPhaseNone(); return; } double recentHigh = iHigh(Symbol(), PERIOD_M5, iHighest(Symbol(), PERIOD_M5, MODE_HIGH, 15, 0)); double moveUp = recentHigh - activeSetup.entry1278Price; double minMove = 20 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; if(moveUp >= minMove) { activeSetup.newSwingHigh = recentHigh; activeSetup.swingEstablished = true; currentPhase = PHASE_618_ADDON; Print("Swing established at ", recentHigh, " - waiting for 61.8% pullback"); } } //+------------------------------------------------------------------+ //| 61.8% ADD-ON ENTRY | //+------------------------------------------------------------------+ void Check618AddonEntry() { if(!activeSetup.swingEstablished) return; double upMove = activeSetup.newSwingHigh - activeSetup.entry1278Price; double fib618Level = activeSetup.newSwingHigh - (upMove * Fib618); double fib786Level = activeSetup.newSwingHigh - (upMove * 0.786); double close15M = iClose(Symbol(), PERIOD_M15, 0); double low15M = iLow(Symbol(), PERIOD_M15, 0); double tolerance = 5 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; if(!(low15M <= fib618Level + tolerance && low15M >= fib786Level - tolerance)) return; if(!Check5M_618Entry(fib618Level, fib786Level)) return; double entryPrice = SymbolInfoDouble(Symbol(), SYMBOL_ASK); double sl = NormalizeDouble(activeSetup.entry1278Price - 5 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10, _Digits); double tp = NormalizeDouble(activeSetup.newSwingHigh + (upMove * 0.5), _Digits); if(ExecuteTrade(ORDER_TYPE_BUY, SecondEntryLots, sl, tp, "618_Addon")) { activeSetup.pullbackLow = low15M; Print("61.8% add-on executed at ", entryPrice); } } //+------------------------------------------------------------------+ //| 5M 61.8% ENTRY WITH STYLE | //+------------------------------------------------------------------+ bool Check5M_618Entry(double fib618, double fib786) { double close5M_0 = iClose(Symbol(), PERIOD_M5, 0); double close5M_1 = iClose(Symbol(), PERIOD_M5, 1); double low5M_0 = iLow(Symbol(), PERIOD_M5, 0); double low5M_1 = iLow(Symbol(), PERIOD_M5, 1); double open5M_0 = iOpen(Symbol(), PERIOD_M5, 0); double high5M_1 = iHigh(Symbol(), PERIOD_M5, 1); double tolerance = 3 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; bool inZone = (low5M_0 <= fib618 + tolerance && low5M_0 >= fib786 - tolerance); if(!inZone) return false; if(EntryMode == STYLE_AGGRESSIVE) { bool doubleBottom = (MathAbs(low5M_0 - low5M_1) < tolerance * 2); bool quickBounce = (low5M_0 <= fib618 && close5M_0 > open5M_0); bool hammer = ((MathMin(close5M_0, open5M_0) - low5M_0) > MathAbs(close5M_0 - open5M_0) * 2); int aggCount = (doubleBottom ? 1 : 0) + (quickBounce ? 1 : 0) + (hammer ? 1 : 0); return (aggCount >= 2); } else { double low5M_2 = iLow(Symbol(), PERIOD_M5, 2); bool higherLow = (low5M_0 > low5M_1 && low5M_1 > low5M_2); bool closeStrong = (close5M_0 > high5M_1); double microRes = iHigh(Symbol(), PERIOD_M5, iHighest(Symbol(), PERIOD_M5, MODE_HIGH, 5, 1)); bool brokeRes = (close5M_0 > microRes); bool momentumOK = BullishDivergenceOnTimeframe(PERIOD_M5); int confCount = (higherLow ? 1 : 0) + (closeStrong ? 1 : 0) + (brokeRes ? 1 : 0) + (momentumOK ? 1 : 0); return (confCount >= 3); } } //+------------------------------------------------------------------+ //| DIVERGENCE CHECKER (Stoch RSI + CCI) | //+------------------------------------------------------------------+ bool BullishDivergenceOnTimeframe(ENUM_TIMEFRAMES tf) { double low1 = iLow(Symbol(), tf, 5); double low2 = iLow(Symbol(), tf, 1); if(low2 >= low1) return false; double stochMain[]; ArraySetAsSeries(stochMain, true); int stochHandle = iStochastic(Symbol(), tf, 14, 3, 3, MODE_SMA, STO_LOWHIGH); if(CopyBuffer(stochHandle, 0, 0, 10, stochMain) < 10) return false; double cci[]; ArraySetAsSeries(cci, true); int cciHandle = iCCI(Symbol(), tf, 20, PRICE_TYPICAL); if(CopyBuffer(cciHandle, 0, 0, 10, cci) < 10) return false; return (stochMain[1] > stochMain[5] && cci[1] > cci[5]); } //+------------------------------------------------------------------+ //| MOMENTUM SCORE | //+------------------------------------------------------------------+ int CalculateMomentumScore() { int score = 0; double rsi = iRSI(Symbol(), PERIOD_M15, 14, PRICE_CLOSE, 0); if(rsi < 30) score += (int)MathMin((30 - rsi) * 1.2, 25); double open = iOpen(Symbol(), PERIOD_M15, 0); double high = iHigh(Symbol(), PERIOD_M15, 0); double low = iLow(Symbol(), PERIOD_M15, 0); double close = iClose(Symbol(), PERIOD_M15, 0); double body = MathAbs(close - open); double lowerWick = MathMin(close, open) - low; if(body > 0 && lowerWick / body > 2.0) score += 25; double stochMain[]; ArraySetAsSeries(stochMain, true); int stochHandle = iStochastic(Symbol(), PERIOD_M15, 14, 3, 3, MODE_SMA, STO_LOWHIGH); CopyBuffer(stochHandle, 0, 0, 1, stochMain); if(stochMain[0] < 15) score += 20; double cci[]; ArraySetAsSeries(cci, true); int cciHandle = iCCI(Symbol(), PERIOD_M15, 20, PRICE_TYPICAL); CopyBuffer(cciHandle, 0, 0, 1, cci); if(cci[0] < -150) score += 20; else if(cci[0] < -100) score += 10; double vwap = iMA(Symbol(), PERIOD_M15, 20, 0, MODE_SMA, PRICE_TYPICAL, 0); double distance = MathAbs(close - vwap) / vwap * 100; score += (int)MathMin(distance * 2, 10); return score; } //+------------------------------------------------------------------+ //| TREND DIRECTION | //+------------------------------------------------------------------+ int GetTrendDirection(ENUM_TIMEFRAMES tf) { double ma50 = iMA(Symbol(), tf, 50, 0, MODE_SMA, PRICE_CLOSE, 0); double ma200 = iMA(Symbol(), tf, 200, 0, MODE_SMA, PRICE_CLOSE, 0); double close = iClose(Symbol(), tf, 0); if(close > ma50 && ma50 > ma200) return 1; if(close < ma50 && ma50 < ma200) return -1; return 0; } //+------------------------------------------------------------------+ //| POSITION MANAGEMENT | //+------------------------------------------------------------------+ void ManagePositions() { bool has1278 = false, has618 = false; double avgEntry = 0, totalLots = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket <= 0) continue; if(PositionGetString(POSITION_SYMBOL) != Symbol()) continue; string comment = PositionGetString(POSITION_COMMENT); int posType = (int)PositionGetInteger(POSITION_TYPE); double lots = PositionGetDouble(POSITION_VOLUME); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); if(StringFind(comment, "1278") != -1) has1278 = true; if(StringFind(comment, "618") != -1) has618 = true; avgEntry += openPrice * lots; totalLots += lots; ManageSinglePosition(ticket, posType, openPrice); } if(totalLots > 0) avgEntry /= totalLots; if(has1278 && has618) ManageAveragedPosition(avgEntry, totalLots); if(!has1278 && !has618 && currentPhase != PHASE_NONE) ResetToPhaseNone(); } //+------------------------------------------------------------------+ //| SINGLE POSITION MANAGEMENT | //+------------------------------------------------------------------+ void ManageSinglePosition(ulong ticket, int posType, double openPrice) { double currentSL = PositionGetDouble(POSITION_SL); double currentTP = PositionGetDouble(POSITION_TP); double currentPrice = (posType == POSITION_TYPE_BUY) ? SymbolInfoDouble(Symbol(), SYMBOL_BID) : SymbolInfoDouble(Symbol(), SYMBOL_ASK); double profitPips = MathAbs(currentPrice - openPrice) / (SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10); // Break even at 15 pips if(profitPips >= 15 && currentSL == 0) { double newSL = openPrice + 2 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; ModifyPosition(ticket, NormalizeDouble(newSL, _Digits), currentTP); } } //+------------------------------------------------------------------+ //| AVERAGED POSITION MANAGEMENT | //+------------------------------------------------------------------+ void ManageAveragedPosition(double avgPrice, double totalLots) { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket <= 0) continue; if(PositionGetString(POSITION_SYMBOL) != Symbol()) continue; int posType = (int)PositionGetInteger(POSITION_TYPE); double currentSL = PositionGetDouble(POSITION_SL); double currentTP = PositionGetDouble(POSITION_TP); double currentPrice = SymbolInfoDouble(Symbol(), SYMBOL_BID); double profitPips = MathAbs(currentPrice - avgPrice) / (SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10); // Breakeven both at +10 pips averaged if(profitPips >= 10 && currentSL < avgPrice) { double newSL = avgPrice + 2 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; ModifyPosition(ticket, NormalizeDouble(newSL, _Digits), currentTP); } // Trail at structure when +40 pips if(profitPips >= 40) { double newSL = GetStructureLevel(PERIOD_M15); double buffer = 3 * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * 10; if(newSL > currentSL) ModifyPosition(ticket, NormalizeDouble(newSL - buffer, _Digits), currentTP); } } } //+------------------------------------------------------------------+ //| GET STRUCTURE LEVEL | //+------------------------------------------------------------------+ double GetStructureLevel(ENUM_TIMEFRAMES tf) { int lowest = iLowest(Symbol(), tf, MODE_LOW, 10, 1); return iLow(Symbol(), tf, lowest); } //+------------------------------------------------------------------+ //| EXECUTE TRADE | //+------------------------------------------------------------------+ bool ExecuteTrade(int direction, double lots, double sl, double tp, string comment) { MqlTradeRequest request = {}; MqlTradeResult result = {}; double price = (direction == ORDER_TYPE_SELL) ? SymbolInfoDouble(Symbol(), SYMBOL_BID) : SymbolInfoDouble(Symbol(), SYMBOL_ASK); request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = lots; request.type = direction; request.price = price; request.sl = sl; request.tp = tp; request.deviation = 10; request.magic = 123456; request.comment = comment; if(!OrderSend(request, result)) { Print("OrderSend failed: ", GetLastError()); return false; } return true; } //+------------------------------------------------------------------+ //| MODIFY POSITION | //+------------------------------------------------------------------+ bool ModifyPosition(ulong ticket, double sl, double tp) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_SLTP; request.position = ticket; request.symbol = Symbol(); request.sl = sl; request.tp = tp; return OrderSend(request, result); } //+------------------------------------------------------------------+ //| CHECK IF HAS OPEN POSITION | //+------------------------------------------------------------------+ bool HasOpenPosition(string keyword) { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket <= 0) continue; if(PositionGetString(POSITION_SYMBOL) != Symbol()) continue; string comment = PositionGetString(POSITION_COMMENT); if(StringFind(comment, keyword) != -1) return true; } return false; } //+------------------------------------------------------------------+ //| RESET SETUP | //+------------------------------------------------------------------+ void ResetToPhaseNone() { currentPhase = PHASE_NONE; activeSetup.swingHigh = 0; activeSetup.swingLow = 0; activeSetup.fib1278Level = 0; activeSetup.entry1278Price = 0; activeSetup.newSwingHigh = 0; activeSetup.swingEstablished = false; Print("Setup reset - hunting for new 127.8% opportunity"); } //+------------------------------------------------------------------+