2026-08-11 09:15:11 +00:00 | | | OUR SMC INDICATOR V1
|
| | |
|
| | | Purpose:
|
| | | Detect only valid setups according to our trading strategy.
|
| | |
|
| | | Core rule:
|
| | | NO CLEAR = NO SIGNAL.
|
2026-08-11 09:19:51 +00:00 | | | 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;
|
2026-08-11 09:21:59 +00:00 | | | 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;
|
2026-08-11 09:24:22 +00:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| 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;
|
2026-08-11 09:27:17 +00:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| 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;
|
| | |
|
2026-08-11 09:29:30 +00:00 | | | 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;
|
| | | }
|
| | |
|
2026-08-11 09:32:25 +00:00 | | | 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;
|
| | | }
|
| | |
|
2026-08-11 09:27:17 +00:00 | | | return false;
|
2026-08-11 09:34:53 +00:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| 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;
|
2026-08-11 09:36:30 +00:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| 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);
|
2026-08-11 09:38:52 +00:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| 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);
|
2026-08-11 09:46:55 +00:00 | | | SendBuyAlert(shift);
|
2026-08-11 09:38:52 +00:00 | | | }
|
| | |
|
| | | // ---------------------------------------------------------------
|
| | | // Check for a valid SELL setup.
|
| | | // ---------------------------------------------------------------
|
| | |
|
| | | if(EnableSellSignals && previousSwingLow > 0.0)
|
| | | {
|
| | | if(ValidSellSetup(shift, previousSwingLow))
|
| | | DrawSellSignal(shift);
|
2026-08-11 09:46:55 +00:00 | | | SendSellAlert(shift);
|
2026-08-11 09:38:52 +00:00 | | | }
|
| | |
|
| | | return rates_total;
|
2026-08-11 09:43:11 +00:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| 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);
|
2026-08-11 09:21:59 +00:00 | | | }
|