431 lines
No EOL
11 KiB
Text
431 lines
No EOL
11 KiB
Text
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);
|
|
} |