OUR SMC INDICATOR V1 Purpose: Detect only valid setups according to our trading strategy. Core rule: NO CLEAR = NO SIGNAL. NO CONFIRMATION = NO TRADE. //+------------------------------------------------------------------+ //| Strategy Settings | //+------------------------------------------------------------------+ input int SwingLookback = 3; input int ConfirmationBars = 1; input bool EnableBuySignals = true; input bool EnableSellSignals = true; input bool ShowStructure = true; input bool ShowSignals = true; input bool EnableAlerts = true; //+------------------------------------------------------------------+ //| Swing Structure Detection | //+------------------------------------------------------------------+ bool IsSwingHigh(int shift) { if(shift < SwingLookback || shift >= Bars(_Symbol,_Period)-SwingLookback) return false; double currentHigh = iHigh(_Symbol,_Period,shift); for(int i=1; i<=SwingLookback; i++) { if(currentHigh <= iHigh(_Symbol,_Period,shift-i)) return false; if(currentHigh <= iHigh(_Symbol,_Period,shift+i)) return false; } return true; } bool IsSwingLow(int shift) { if(shift < SwingLookback || shift >= Bars(_Symbol,_Period)-SwingLookback) return false; double currentLow = iLow(_Symbol,_Period,shift); for(int i=1; i<=SwingLookback; i++) { if(currentLow >= iLow(_Symbol,_Period,shift-i)) return false; if(currentLow >= iLow(_Symbol,_Period,shift+i)) return false; } return true; } //+------------------------------------------------------------------+ //| HH / HL / LH / LL Classification | //+------------------------------------------------------------------+ enum StructureType { STRUCTURE_NONE, STRUCTURE_HH, STRUCTURE_HL, STRUCTURE_LH, STRUCTURE_LL }; StructureType GetHighStructure(double currentHigh, double previousHigh) { if(currentHigh > previousHigh) return STRUCTURE_HH; if(currentHigh < previousHigh) return STRUCTURE_LH; return STRUCTURE_NONE; } StructureType GetLowStructure(double currentLow, double previousLow) { if(currentLow > previousLow) return STRUCTURE_HL; if(currentLow < previousLow) return STRUCTURE_LL; return STRUCTURE_NONE; } //+------------------------------------------------------------------+ //| Break of Structure (BOS) Detection | //+------------------------------------------------------------------+ bool BullishBOS(int shift, double previousSwingHigh) { double closePrice = iClose(_Symbol, _Period, shift); // Bullish BOS requires a candle CLOSE above the previous swing high. if(closePrice > previousSwingHigh) return true; return false; } bool BearishBOS(int shift, double previousSwingLow) { double closePrice = iClose(_Symbol, _Period, shift); // Bearish BOS requires a candle CLOSE below the previous swing low. if(closePrice < previousSwingLow) return true; return false; } //+------------------------------------------------------------------+ //| Pullback / Retest Detection | //+------------------------------------------------------------------+ bool BullishRetest(int shift, double brokenResistance) { double candleLow = iLow(_Symbol, _Period, shift); double candleClose = iClose(_Symbol, _Period, shift); // Price must return to the broken level // and close back above it. if(candleLow <= brokenResistance && candleClose > brokenResistance) { return true; } return false; } bool BearishRetest(int shift, double brokenSupport) { double candleHigh = iHigh(_Symbol, _Period, shift); double candleClose = iClose(_Symbol, _Period, shift); // Price must return to the broken level // and close back below it. if(candleHigh >= brokenSupport && candleClose < brokenSupport) { return true; } return false; } //+------------------------------------------------------------------+ //| Confirmation Candle Detection | //+------------------------------------------------------------------+ bool BullishConfirmation(int shift) { double openPrice = iOpen(_Symbol, _Period, shift); double closePrice = iClose(_Symbol, _Period, shift); double highPrice = iHigh(_Symbol, _Period, shift); double lowPrice = iLow(_Symbol, _Period, shift); double bodySize = MathAbs(closePrice - openPrice); double totalSize = highPrice - lowPrice; if(totalSize <= 0) return false; // Bullish candle must close above its open. // Require the candle body to represent at least // half of the complete candle range. if(closePrice > openPrice && bodySize >= totalSize * 0.50) { return true; } return false; } bool BearishConfirmation(int shift) { double openPrice = iOpen(_Symbol, _Period, shift); double closePrice = iClose(_Symbol, _Period, shift); double highPrice = iHigh(_Symbol, _Period, shift); double lowPrice = iLow(_Symbol, _Period, shift); double bodySize = MathAbs(closePrice - openPrice); double totalSize = highPrice - lowPrice; if(totalSize <= 0) return false; // Bearish candle must close below its open. // Require the candle body to represent at least // half of the complete candle range. if(closePrice < openPrice && bodySize >= totalSize * 0.50) { return true; } return false; } //+------------------------------------------------------------------+ //| BUY / SELL Signal Engine | //+------------------------------------------------------------------+ bool ValidBuySetup(int shift, double previousSwingHigh) { // Step 1: Bullish BOS if(!BullishBOS(shift, previousSwingHigh)) return false; // Step 2: Pullback / retest if(!BullishRetest(shift, previousSwingHigh)) return false; // Step 3: Confirmation candle if(!BullishConfirmation(shift)) return false; return true; } bool ValidSellSetup(int shift, double previousSwingLow) { // Step 1: Bearish BOS if(!BearishBOS(shift, previousSwingLow)) return false; // Step 2: Pullback / retest if(!BearishRetest(shift, previousSwingLow)) return false; // Step 3: Confirmation candle if(!BearishConfirmation(shift)) return false; return true; } //+------------------------------------------------------------------+ //| Signal Display | //+------------------------------------------------------------------+ void DrawBuySignal(int shift) { if(!ShowSignals) return; datetime signalTime = iTime(_Symbol, _Period, shift); double signalPrice = iLow(_Symbol, _Period, shift); string name = "SMC_BUY_" + IntegerToString((int)signalTime); if(ObjectFind(0, name) >= 0) return; ObjectCreate(0, name, OBJ_ARROW_BUY, 0, signalTime, signalPrice); ObjectSetInteger(0, name, OBJPROP_WIDTH, 2); } void DrawSellSignal(int shift) { if(!ShowSignals) return; datetime signalTime = iTime(_Symbol, _Period, shift); double signalPrice = iHigh(_Symbol, _Period, shift); string name = "SMC_SELL_" + IntegerToString((int)signalTime); if(ObjectFind(0, name) >= 0) return; ObjectCreate(0, name, OBJ_ARROW_SELL, 0, signalTime, signalPrice); ObjectSetInteger(0, name, OBJPROP_WIDTH, 2); } //+------------------------------------------------------------------+ //| Main Chart Scanner | //+------------------------------------------------------------------+ int OnCalculate( const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[] ) { // We need enough candles to identify structure. int minimumBars = (SwingLookback * 2) + 10; if(rates_total < minimumBars) return 0; // Only process the most recently closed candle. // Shift 1 = last completed candle. int shift = 1; // --------------------------------------------------------------- // Find the most recent confirmed swing high and swing low. // --------------------------------------------------------------- double previousSwingHigh = 0.0; double previousSwingLow = 0.0; for(int i = shift + SwingLookback; i < rates_total - SwingLookback; i++) { if(IsSwingHigh(i)) { previousSwingHigh = iHigh(_Symbol, _Period, i); break; } } for(int i = shift + SwingLookback; i < rates_total - SwingLookback; i++) { if(IsSwingLow(i)) { previousSwingLow = iLow(_Symbol, _Period, i); break; } } // --------------------------------------------------------------- // Check for a valid BUY setup. // --------------------------------------------------------------- if(EnableBuySignals && previousSwingHigh > 0.0) { if(ValidBuySetup(shift, previousSwingHigh)) DrawBuySignal(shift); SendBuyAlert(shift); } // --------------------------------------------------------------- // Check for a valid SELL setup. // --------------------------------------------------------------- if(EnableSellSignals && previousSwingLow > 0.0) { if(ValidSellSetup(shift, previousSwingLow)) DrawSellSignal(shift); SendSellAlert(shift); } return rates_total; } //+------------------------------------------------------------------+ //| Alert System | //+------------------------------------------------------------------+ datetime LastBuyAlertTime = 0; datetime LastSellAlertTime = 0; void SendBuyAlert(int shift) { if(!EnableAlerts) return; datetime signalTime = iTime(_Symbol, _Period, shift); // Prevent repeated alerts for the same candle. if(signalTime == LastBuyAlertTime) return; LastBuyAlertTime = signalTime; string message = _Symbol + " " + EnumToString(_Period) + " - SMC BUY setup confirmed"; Alert(message); Print(message); } void SendSellAlert(int shift) { if(!EnableAlerts) return; datetime signalTime = iTime(_Symbol, _Period, shift); // Prevent repeated alerts for the same candle. if(signalTime == LastSellAlertTime) return; LastSellAlertTime = signalTime; string message = _Symbol + " " + EnumToString(_Period) + " - SMC SELL setup confirmed"; Alert(message); Print(message); }