//+------------------------------------------------------------------+
//| SNRC_OrderBlock_Indicator.mq5 |
//| Telif Hakkı 2025, AYDIN SARIHAN (Geliştirildi) |
//| https://www.mql5.com/en/users/aydinsarihan|
//+------------------------------------------------------------------+
#property copyright "Copyright © 2025, AYDIN SARIHAN (Developed by AI)"
#property link "https://www.mql5.com/en/users/aydinsarihan"
#property version "1.00"
#property strict
#property indicator_chart_window
#property description "SNRC QUASİDAMO ENGULF TRENDLINE metodolojisine göre Order Block'ları tespit eder."
/// Değişiklik: Kod, sağlanan direktife ve SNRC kurallarına göre sıfırdan yapılandırıldı.
/// Değişiklik: Çok zaman dilimli (MTF) analiz mantığı eklendi.
/// Değişiklik: RBR ve DBD formasyon tespiti eklendi.
/// Değişiklik: Nesne yönetimi ve mitigasyon kontrolü eklendi.
//==================================================================
// BÖLÜM 1: DAHİL EDİLENLER & KÜTÜPHANELER
//==================================================================
// Bu gösterge için ek kütüphane gerekmemektedir.
//==================================================================
// BÖLÜM 2: GİRİŞ PARAMETRELERİ (INPUTS)
//==================================================================
input group "Zaman Dilimi Ayarları (MTF)";
input ENUM_TIMEFRAMES HTF_Timeframe = PERIOD_H4; // Yüksek Zaman Dilimi (Engulfing tespiti için)
input int HTF_Lookback_Bars = 100; // HTF'de taranacak mum sayısı
input group "Formasyon Tanımlama Ayarları";
input double Base_Candle_Max_Body_Ratio = 0.3; // Bir mumun 'Base' sayılması için (Gövde/Toplam Boyut) oranı
input int Max_Base_Candles = 5; // Bir Base bölgesindeki maksimum mum sayısı
input group "Görsel Ayarlar";
input color Bullish_OB_Color = clrDodgerBlue; // Yükseliş (Bullish) Order Block rengi
input color Bearish_OB_Color = clrTomato; // Düşüş (Bearish) Order Block rengi
input color Mitigated_OB_Color = clrGray; // Mitige edilmiş (temas edilmiş) OB rengi
input bool Fill_Order_Block = true; // Order Block içini doldur
input bool Delete_Mitigated_OB = false; // Mitige edilmiş OB'leri sil
//==================================================================
// BÖLÜM 3: GLOBAL DEĞİŞKENLER & SABİTLER
//==================================================================
//--- Yapılar
struct OrderBlock
{
double price_high; // OB üst sınırı
double price_low; // OB alt sınırı
datetime time_start; // OB başlangıç zamanı
string name; // Grafik nesnesi adı
bool is_bullish; // true: Bullish OB, false: Bearish OB
bool is_mitigated; // Mitigasyon durumu
};
//--- Global Değişklenler
OrderBlock g_order_blocks[]; // Tespit edilen tüm order block'ları saklayan dizi
datetime g_lastBarTime; // Yeni bar kontrolü için son bar zamanı
// Sinyal enum (Direktif uyumlu)
enum ENUM_SIGNAL { SIGNAL_BULLISH, SIGNAL_BEARISH, SIGNAL_NONE };
//==================================================================
// BÖLÜM 4: ANA OLAY YÖNETİCİLERİ (MAIN EVENT HANDLERS)
//==================================================================
//+------------------------------------------------------------------+
//| Başlatma fonksiyonu |
//+------------------------------------------------------------------+
int OnInit()
{
if(_Period >= HTF_Timeframe)
{
Print("Hata: Göstergenin zaman dilimi, HTF_Timeframe'den küçük olmalıdır.");
return(INIT_PARAMETERS_INCORRECT);
}
ArrayResize(g_order_blocks, 0);
g_lastBarTime = 0;
Print("Başlatıldı: ", MQLInfoString(MQL_PROGRAM_NAME));
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Durdurma fonksiyonu |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, "SNRC_OB_");
Print("Durduruldu. Sebep: ", reason);
}
//+------------------------------------------------------------------+
//| Ana Döngü Fonksiyonu (Indicator) |
//+------------------------------------------------------------------+
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[])
{
//--- Yeni bar kontrolü
if(time[rates_total - 1] == g_lastBarTime)
{
CheckMitigation(rates_total, high, low); // Sadece mitigasyon kontrolü yap
return(rates_total);
}
g_lastBarTime = time[rates_total - 1];
//--- Ana Mantık
FindOrderBlocks(rates_total, time);
CheckMitigation(rates_total, high, low);
DrawOrderBlocks();
return(rates_total);
}
//==================================================================
// BÖLÜM 5: STRATEJİ & HESAPLAMA MANTIĞI
//==================================================================
///
/// Ana fonksiyon: HTF'de Engulfing arar ve LTF'de OB tespiti için mantığı tetikler.
///
void FindOrderBlocks(const int rates_total, const datetime &time[])
{
MqlRates htf_rates[];
// HTF verilerini kopyala
if(CopyRates(Symbol(), HTF_Timeframe, 0, HTF_Lookback_Bars, htf_rates) < HTF_Lookback_Bars)
{
Print("HTF verileri kopyalanamadı.");
return;
}
ArraySetAsSeries(htf_rates, true);
// HTF mumlarını tara
for(int i = 0; i < HTF_Lookback_Bars - 2; i++)
{
ENUM_SIGNAL signal = Is_HTF_Engulfing(htf_rates, i);
if(signal != SIGNAL_NONE)
{
// Engulfing bulundu, şimdi LTF'de ilgili aralıkta OB ara
datetime htf_candle_start_time = htf_rates[i].time;
datetime htf_candle_end_time = htf_rates[i].time + PeriodSeconds(HTF_Timeframe);
// LTF (mevcut grafik) bar indekslerini bul
int ltf_start_index = iBarShift(Symbol(), Period(), htf_candle_start_time);
int ltf_end_index = iBarShift(Symbol(), Period(), htf_candle_end_time);
if(ltf_end_index < 0) ltf_end_index = 0; // Henüz kapanmamış mum için
Find_LTF_Pattern_And_Create_OB(signal, ltf_start_index, ltf_end_index);
}
}
}
///
/// Belirtilen HTF mumunun Engulfing olup olmadığını kontrol eder.
///
/// HTF fiyat verileri.
/// Kontrol edilecek mumun indeksi.
/// SIGNAL_BULLISH, SIGNAL_BEARISH, veya SIGNAL_NONE.
ENUM_SIGNAL Is_HTF_Engulfing(const MqlRates &htf_rates[], int index)
{
// Bullish Engulfing
if(htf_rates[index].close > htf_rates[index].open && // Mevcut mum bullish
htf_rates[index+1].close < htf_rates[index+1].open && // Önceki mum bearish
htf_rates[index].close > htf_rates[index+1].open && // Mevcut kapanış, önceki açılışın üstünde
htf_rates[index].open < htf_rates[index+1].close) // Mevcut açılış, önceki kapanışın altında
{
return SIGNAL_BULLISH;
}
// Bearish Engulfing
if(htf_rates[index].close < htf_rates[index].open && // Mevcut mum bearish
htf_rates[index+1].close > htf_rates[index+1].open && // Önceki mum bullish
htf_rates[index].close < htf_rates[index+1].open && // Mevcut kapanış, önceki açılışın altında
htf_rates[index].open > htf_rates[index+1].close) // Mevcut açılış, önceki kapanışın üstünde
{
return SIGNAL_BEARISH;
}
return SIGNAL_NONE;
}
///
/// LTF'de (mevcut grafik) RBR veya DBD formasyonu arar ve OB oluşturur.
///
/// HTF Engulfing yönü (BULLISH/BEARISH).
/// Aramanın başlayacağı bar indeksi.
/// Aramanın biteceği bar indeksi.
void Find_LTF_Pattern_And_Create_OB(ENUM_SIGNAL direction, int start_index, int end_index)
{
MqlRates ltf_rates[];
if(CopyRates(Symbol(), Period(), end_index, start_index - end_index + 1, ltf_rates) <= 0) return;
ArraySetAsSeries(ltf_rates, false); // İndeksleme 0'dan başlasın
// SNRC Kuralı: Bullish HTF Engulf -> LTF'de DBD ara
if(direction == SIGNAL_BULLISH)
{
// Yükselişten (Rally) önceki son Base'i bul
for(int i = ArraySize(ltf_rates) - 2; i > Max_Base_Candles; i--)
{
// Son mumun güçlü bir yükseliş olduğunu kontrol et (Rally)
if(ltf_rates[i].close > ltf_rates[i].open && !IsBaseCandle(ltf_rates[i]))
{
int base_start_index = -1, base_end_index = -1;
// Geriye doğru Base mumlarını ara
for(int j = 1; j <= Max_Base_Candles; j++)
{
if(IsBaseCandle(ltf_rates[i-j]))
{
if(base_start_index == -1) base_start_index = i-j;
base_end_index = i-j;
}
else break; // Base serisi bitti
}
// Eğer bir base bölgesi bulunduysa
if(base_start_index != -1)
{
// Base'den önce bir düşüş (Drop) olduğunu onayla
if(ltf_rates[base_end_index - 1].close < ltf_rates[base_end_index - 1].open)
{
// DBD bulundu, Order Block oluştur
double ob_high = ltf_rates[base_end_index].high;
double ob_low = ltf_rates[base_end_index].low;
for(int k=base_end_index + 1; k <= base_start_index; k++)
{
ob_high = MathMax(ob_high, ltf_rates[k].high);
ob_low = MathMin(ob_low, ltf_rates[k].low);
}
datetime ob_time = ltf_rates[base_end_index].time;
AddOrderBlock(ob_high, ob_low, ob_time, true);
return; // Bu HTF mumu için bir OB bulundu, aramayı bitir.
}
}
}
}
}
// SNRC Kuralı: Bearish HTF Engulf -> LTF'de RBR ara
else if(direction == SIGNAL_BEARISH)
{
// Düşüşten (Drop) önceki son Base'i bul
for(int i = ArraySize(ltf_rates) - 2; i > Max_Base_Candles; i--)
{
// Son mumun güçlü bir düşüş olduğunu kontrol et (Drop)
if(ltf_rates[i].close < ltf_rates[i].open && !IsBaseCandle(ltf_rates[i]))
{
int base_start_index = -1, base_end_index = -1;
// Geriye doğru Base mumlarını ara
for(int j = 1; j <= Max_Base_Candles; j++)
{
if(IsBaseCandle(ltf_rates[i-j]))
{
if(base_start_index == -1) base_start_index = i-j;
base_end_index = i-j;
}
else break; // Base serisi bitti
}
// Eğer bir base bölgesi bulunduysa
if(base_start_index != -1)
{
// Base'den önce bir yükseliş (Rally) olduğunu onayla
if(ltf_rates[base_end_index - 1].close > ltf_rates[base_end_index - 1].open)
{
// RBR bulundu, Order Block oluştur
double ob_high = ltf_rates[base_end_index].high;
double ob_low = ltf_rates[base_end_index].low;
for(int k=base_end_index + 1; k <= base_start_index; k++)
{
ob_high = MathMax(ob_high, ltf_rates[k].high);
ob_low = MathMin(ob_low, ltf_rates[k].low);
}
datetime ob_time = ltf_rates[base_end_index].time;
AddOrderBlock(ob_high, ob_low, ob_time, false);
return; // Bu HTF mumu için bir OB bulundu, aramayı bitir.
}
}
}
}
}
}
//==================================================================
// BÖLÜM 8: YARDIMCI FONKSİYONLAR
//==================================================================
///
/// Bir mumun 'Base' (konsolidasyon) mumu olup olmadığını kontrol eder.
///
bool IsBaseCandle(const MqlRates &rate)
{
double body = MathAbs(rate.open - rate.close);
double total_range = rate.high - rate.low;
if(total_range == 0) return true; // Doji
return (body / total_range) < Base_Candle_Max_Body_Ratio;
}
///
/// Tespit edilen Order Block'u global diziye ekler.
///
void AddOrderBlock(double price_high, double price_low, datetime time_start, bool is_bullish)
{
// Duplikasyon kontrolü
for(int i=0; i < ArraySize(g_order_blocks); i++)
{
if(g_order_blocks[i].time_start == time_start)
return; // Zaten mevcut, ekleme
}
int last_index = ArraySize(g_order_blocks);
ArrayResize(g_order_blocks, last_index + 1);
g_order_blocks[last_index].price_high = price_high;
g_order_blocks[last_index].price_low = price_low;
g_order_blocks[last_index].time_start = time_start;
g_order_blocks[last_index].is_bullish = is_bullish;
g_order_blocks[last_index].is_mitigated = false;
g_order_blocks[last_index].name = "SNRC_OB_" + TimeToString(time_start, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
}
///
/// Mevcut fiyatın Order Block'ları mitige edip etmediğini kontrol eder.
///
void CheckMitigation(int rates_total, const double &high[], const double &low[])
{
if(rates_total < 1) return;
double current_high = high[rates_total - 1];
double current_low = low[rates_total - 1];
for(int i=0; i < ArraySize(g_order_blocks); i++)
{
if(g_order_blocks[i].is_mitigated) continue;
// Bullish OB Mitigasyonu: Fiyat OB'nin alt sınırına değerse
if(g_order_blocks[i].is_bullish && current_low <= g_order_blocks[i].price_high)
{
g_order_blocks[i].is_mitigated = true;
}
// Bearish OB Mitigasyonu: Fiyat OB'nin üst sınırına değerse
else if(!g_order_blocks[i].is_bullish && current_high >= g_order_blocks[i].price_low)
{
g_order_blocks[i].is_mitigated = true;
}
}
}
///
/// Order Block'ları grafiğe çizer veya günceller.
///
void DrawOrderBlocks()
{
datetime current_time = iTime(Symbol(), Period(), 0);
for(int i=0; i < ArraySize(g_order_blocks); i++)
{
OrderBlock ob = g_order_blocks[i];
if(ob.is_mitigated && Delete_Mitigated_OB)
{
ObjectDelete(0, ob.name);
continue;
}
// Çizim için renk belirle
color ob_color;
if(ob.is_mitigated)
ob_color = Mitigated_OB_Color;
else
ob_color = ob.is_bullish ? Bullish_OB_Color : Bearish_OB_Color;
// Nesne var mı kontrol et
if(ObjectFind(0, ob.name) < 0) // Nesne yok, oluştur
{
ObjectCreate(0, ob.name, OBJ_RECTANGLE, 0, ob.time_start, ob.price_low, current_time, ob.price_high);
ObjectSetInteger(0, ob.name, OBJPROP_COLOR, ob_color);
ObjectSetInteger(0, ob.name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, ob.name, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, ob.name, OBJPROP_FILL, Fill_Order_Block);
ObjectSetInteger(0, ob.name, OBJPROP_BACK, true);
ObjectSetString(0, ob.name, OBJPROP_TOOLTIP, (ob.is_bullish ? "Bullish OB" : "Bearish OB"));
}
else // Nesne var, güncelle
{
ObjectMove(0, ob.name, 2, current_time, ob.price_high);
ObjectSetInteger(0, ob.name, OBJPROP_COLOR, ob_color);
}
}
}