//+------------------------------------------------------------------+ //| SNR_AV_v5.mq5 | //| Telif Hakkı 2025, AYDIN SARIHAN | //| https://www.mql5.com/en/users/aydinsarihan | //+------------------------------------------------------------------+ #property copyright "Copyright © 2025, AYDIN SARIHAN" #property link "https://www.mql5.com/en/users/aydinsarihan" #property version "1.05" #property strict #property description "Destek/Direnç seviyeleri ve A/V keskinliği" #property indicator_chart_window #property indicator_plots 0 //================================================================== // BÖLÜM 1: DAHİL EDİLENLER & KÜTÜPHANELER //================================================================== // Bu indikatör için ek kütüphane gerekmemektedir. //================================================================== // BÖLÜM 2: GİRİŞ PARAMETRELERİ (INPUTS) //================================================================== input group "Seviye Belirleme (Sekanas § Tabanlı)" input int Depth = 1; // A/V tepe/dip için sağ-sol bar sayısı (1 önerilir) input double MinSharpnessSekanas = 3.0; // A/V keskinlik eşiği (Sekanas §) input double MergeTolSekanas = 5.0; // Yakın seviyeleri birleştirme toleransı (Sekanas §) input bool UseDynamicMaxLevels = false; // Zaman dilimine göre max seviye sayısı? input int DefaultMaxLevels = 12; // Dinamik kapalıysa kullanılacak max seviye input group "Zaman Dilimi Geçmişi (Saat Cinsinden)" input int LookbackHours_D1 = 2160; // (3 Ay) D1 analiz input int LookbackHours_H4 = 1440; // (2 Ay) H4 analiz input int LookbackHours_H1 = 720; // (1 Ay) H1 analiz input group "Görsel Ayarlar (Mevcut Zaman Dilimi için)" input int LookbackBarsForDrawing = 250; // Seviyelerin geçmişte kaç bar boyunca çizileceği input int LineExtensionBars = 2; // Çizgilerin sağa (geleceğe) uzatılacağı bar sayısı input color ColorSupport = clrLimeGreen; input color ColorResistance = clrTomato; input color ColorBroken = clrYellowGreen; // Kırılmış (rol değiştirmiş) seviye rengi input group "MTF Ayarları (Çoklu Zaman Dilimi)" input bool Show_D1 = true; input color Color_D1 = clrGray; input bool Show_H4 = true; input color Color_H4 = clrOrange; input bool Show_H1 = true; input color Color_H1 = clrMediumSeaGreen; input group "Geliştirici" input bool EnableDebugMode = false; // 'true' ise Uzmanlar sekmesine bilgi yazdırır //================================================================== // BÖLÜM 3: GLOBAL DEĞİŞKENLER & SABİTLER //================================================================== const string PREFIX = "AV_SRA_SK_"; #define BTN_NAME_TOGGLE_LINES "AV_SR_BTN_TOGGLE" bool g_show_lines = true; //--- Yapılar (Structs) struct Level { double p; int touches; long first_touch_time; long last_touch_time; int dominant_type; // 1=Direnç (A), -1=Destek (V) }; struct Node { int i; double p; datetime t; bool isHigh; }; //================================================================== // BÖLÜM 4: ANA OLAY YÖNETİCİLERİ (MAIN EVENT HANDLERS) //================================================================== int OnInit() { IndicatorSetString(INDICATOR_SHORTNAME, "SNR_AV_v4"); CreatePanel(); UpdatePanel(); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { DeleteWithPrefix(PREFIX); ObjectDelete(0, BTN_NAME_TOGGLE_LINES); } void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { if(id == CHARTEVENT_OBJECT_CLICK) { if(sparam == BTN_NAME_TOGGLE_LINES) { g_show_lines = !g_show_lines; UpdatePanel(); RedrawAllObjects(); ChartRedraw(); } } } 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[]) { static datetime last_bar_time = 0; // Sadece yeni mum açılışlarında (kapanış bittiğinde) güncelleme yap if(rates_total > 0 && time[rates_total - 1] == last_bar_time && prev_calculated > 0) { return(rates_total); } if(rates_total > 0) { last_bar_time = time[rates_total - 1]; } RedrawAllObjects(); ChartRedraw(); return(rates_total); } //================================================================== // BÖLÜM 5: STRATEJİ & HESAPLAMA MANTIĞI //================================================================== void ProcessAndDrawSR(ENUM_TIMEFRAMES timeframe) { int hours = 720; if(timeframe == PERIOD_D1) hours = LookbackHours_D1; else if(timeframe == PERIOD_H4) hours = LookbackHours_H4; else if(timeframe == PERIOD_H1) hours = LookbackHours_H1; datetime end_t = TimeCurrent(); datetime start_t = end_t - (hours * 3600); // Belirlenen saat kadar geriye git int lookback = Bars(_Symbol, timeframe, start_t, end_t); if(lookback < Depth * 2 + 5) lookback = 100; // Güvenlik amacıyla minimum bar MqlRates rates[]; // DİKKAT: İndeks 1'den başlayarak kopyalanıyor (Sadece KAPANMIŞ mumlar hesaba katılır) int bars = CopyRates(_Symbol, timeframe, 1, lookback, rates); if(bars <= Depth * 2) return; ArraySetAsSeries(rates, true); double mergeTolPrice = SekanasToPriceDifference(MergeTolSekanas); double sharpPrice = SekanasToPriceDifference(MinSharpnessSekanas); Node nodes[]; for(int i = Depth; i < bars - Depth; ++i) { double c = rates[i].close; bool isLocalHigh = true, isLocalLow = true; for(int k = 1; k <= Depth; k++) { if(!(c > rates[i - k].close && c > rates[i + k].close)) isLocalHigh = false; if(!(c < rates[i - k].close && c < rates[i + k].close)) isLocalLow = false; if(!isLocalHigh && !isLocalLow) break; } if(isLocalHigh || isLocalLow) { if(MathAbs(rates[i - 1].close - c) + MathAbs(rates[i + 1].close - c) < sharpPrice) continue; Node n; n.i = i; n.p = c; n.t = rates[i].time; n.isHigh = isLocalHigh; int sz = ArraySize(nodes); ArrayResize(nodes, sz + 1); nodes[sz] = n; } } Level levels[]; for(int n = 0; n < ArraySize(nodes); ++n) { bool merged = false; for(int m = 0; m < ArraySize(levels); ++m) { if(MathAbs(levels[m].p - nodes[n].p) <= mergeTolPrice) { levels[m].p = (levels[m].p * levels[m].touches + nodes[n].p) / (levels[m].touches + 1); levels[m].touches++; levels[m].last_touch_time = MathMax(levels[m].last_touch_time, nodes[n].t); merged = true; break; } } if(!merged){ Level L; L.p = nodes[n].p; L.touches = 1; L.first_touch_time = nodes[n].t; L.last_touch_time = nodes[n].t; L.dominant_type = nodes[n].isHigh ? 1 : -1; int sz = ArraySize(levels); ArrayResize(levels, sz + 1); levels[sz] = L; } } int levels_count = ArraySize(levels); for(int i = 0; i < levels_count - 1; i++){ for(int j = i + 1; j < levels_count; j++){ if(levels[j].last_touch_time > levels[i].last_touch_time){ SwapLevels(levels, i, j); } } } int maxLevelsToShow = UseDynamicMaxLevels ? GetMaxLevelsForTimeframe() : DefaultMaxLevels; int levelsToDraw = MathMin(maxLevelsToShow, levels_count); double current_close = rates[0].close; // Artık rates[0] en son KAPANMIŞ mumdur MqlRates current_tf_rates[]; int bars_for_drawing = CopyRates(_Symbol, _Period, 1, LookbackBarsForDrawing, current_tf_rates); datetime drawing_window_start_time = 0; if(bars_for_drawing > 0){ ArraySetAsSeries(current_tf_rates, true); drawing_window_start_time = current_tf_rates[bars_for_drawing - 1].time; } // Bitiş Zamanını İleriye (Geleceğe) Taşıma Mantığı datetime endTime = 0; if(bars_for_drawing > 0) { // Son kapanan barın zamanına, belirtilen bar sayısı kadar saniye ekleyerek çizgiyi uzatıyoruz endTime = current_tf_rates[0].time + (PeriodSeconds() * LineExtensionBars); } string tf_label; color level_color, broken_color; GetTimeframeParameters(timeframe, tf_label, level_color, broken_color); for(int i = 0; i < levelsToDraw; i++) { string baseName = PREFIX + tf_label + "_L_" + IntegerToString(i); double priceLvl = levels[i].p; color lineColor = (levels[i].dominant_type == 1 && current_close > priceLvl) || (levels[i].dominant_type == -1 && current_close < priceLvl) ? broken_color : level_color; int lineStyle = (levels[i].dominant_type == 1 && current_close > priceLvl) || (levels[i].dominant_type == -1 && current_close < priceLvl) ? STYLE_DOT : STYLE_SOLID; int width = (int)MathMin(5, 1 + (levels[i].touches / 2)); datetime actualStartTime = (datetime)MathMax(drawing_window_start_time, levels[i].first_touch_time); ObjectCreate(0, baseName, OBJ_TREND, 0, actualStartTime, priceLvl, endTime, priceLvl); ObjectSetInteger(0, baseName, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, baseName, OBJPROP_STYLE, lineStyle); ObjectSetInteger(0, baseName, OBJPROP_WIDTH, width); ObjectSetInteger(0, baseName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, baseName, OBJPROP_RAY_RIGHT, false); string textName = baseName + "_text"; // Yazıyı çizginin bittiği noktanın 1 bar ilerisine yerleştiriyoruz ki çizgiden ayrık ve okunabilir olsun datetime text_time_coord = endTime + (PeriodSeconds() * 1); string touch_text = StringFormat("%s, T:%d", tf_label, levels[i].touches); ObjectCreate(0, textName, OBJ_TEXT, 0, text_time_coord, priceLvl); ObjectSetString(0, textName, OBJPROP_TEXT, touch_text); ObjectSetInteger(0, textName, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, textName, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, textName, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); ObjectSetInteger(0, textName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, textName, OBJPROP_BACK, true); } } //================================================================== // BÖLÜM 8: YARDIMCI FONKSİYONLAR //================================================================== void RedrawAllObjects() { DeleteWithPrefix(PREFIX); if(!g_show_lines) { return; } if(EnableDebugMode) Print("Redrawing all objects for ", _Symbol, " ", EnumToString(_Period)); ENUM_TIMEFRAMES current_tf = _Period; if(current_tf >= PERIOD_D1) { if(Show_D1) ProcessAndDrawSR(PERIOD_D1); } else if(current_tf == PERIOD_H4) { if(Show_D1) ProcessAndDrawSR(PERIOD_D1); if(Show_H4) ProcessAndDrawSR(PERIOD_H4); } else if(current_tf <= PERIOD_H1) { if(Show_D1) ProcessAndDrawSR(PERIOD_D1); if(Show_H4) ProcessAndDrawSR(PERIOD_H4); if(Show_H1) ProcessAndDrawSR(PERIOD_H1); } } void CreatePanel() { ObjectCreate(0, BTN_NAME_TOGGLE_LINES, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_YDISTANCE, 30); // Eksenle çakışmaması için biraz yükseltildi ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_XSIZE, 120); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_YSIZE, 20); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_FONTSIZE, 9); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_CORNER, CORNER_LEFT_LOWER); // Buton Sol Alta Alındı ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_SELECTABLE, false); } void UpdatePanel() { string text = g_show_lines ? "A V Lines Off" : "A V Lines On"; ObjectSetString(0, BTN_NAME_TOGGLE_LINES, OBJPROP_TEXT, text); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_STATE, !g_show_lines); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_BGCOLOR, !g_show_lines ? clrGray : clrWhiteSmoke); ObjectSetInteger(0, BTN_NAME_TOGGLE_LINES, OBJPROP_COLOR, !g_show_lines ? clrWhite : clrBlack); } double SekanasToPriceDifference(double sekanas_value) { double anlik_fiyat = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(anlik_fiyat == 0) return 0.0; double bir_sekanaslik_fiyat_hareketi = anlik_fiyat * 0.0001; return bir_sekanaslik_fiyat_hareketi * sekanas_value; } void DeleteWithPrefix(const string &pref) { for(int i = ObjectsTotal(0, 0, -1) - 1; i >= 0; i--) { string name = ObjectName(0, i, 0, -1); if(StringFind(name, pref) == 0) ObjectDelete(0, name); } } int GetMaxLevelsForTimeframe() { switch((ENUM_TIMEFRAMES)_Period) { case PERIOD_D1: return 4; case PERIOD_H4: return 5; case PERIOD_H1: return 8; default: return DefaultMaxLevels; } } void SwapLevels(Level &levels_array[], int index1, int index2) { Level temp = levels_array[index1]; levels_array[index1] = levels_array[index2]; levels_array[index2] = temp; } void GetTimeframeParameters(ENUM_TIMEFRAMES tf, string &label, color &lvl_color, color &brk_color) { switch(tf) { case PERIOD_D1: label = "D1"; lvl_color = Color_D1; brk_color = Color_D1; break; case PERIOD_H4: label = "H4"; lvl_color = Color_H4; brk_color = Color_H4; break; case PERIOD_H1: label = "H1"; lvl_color = Color_H1; brk_color = Color_H1; break; default: label = EnumToString(tf); lvl_color = clrGold; brk_color = ColorBroken; break; } } //+------------------------------------------------------------------+