//+------------------------------------------------------------------+ //| HeikinAS.mq5 | //| Copyright © 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.50" /// Değişiklik: Tick sayacı kaldırıldı, Geçmiş Çizim Limiti ve Renk Karartma eklendi. #define _NAME_ " HeikinAS" #property strict #property indicator_chart_window //--- Buffer Ayarları #ifdef __MQL5__ #property indicator_buffers 8 #property indicator_plots 1 #property indicator_label1 "dhaOpen;dhaHigh;dhaLow;dhaClose" #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 clrGreen, clrFireBrick, clrGold #else #property indicator_buffers 4 #endif //================================================================== // BÖLÜM 2: GİRİŞ PARAMETRELERİ (INPUTS) //================================================================== input group "Heikin Ashi Ayarları"; input double dblPeriod = 3.0; // Ortalama Periyodu input bool boolZeroLag = false; // Zero-Lag EMA Kullan input bool boolLineGraph = true; // Çizgi Grafik Modu input bool boolHideLine = false; // Kapanış Çizgisini Gizle input group "Görsel Takip Ayarları"; input int HistoryDepth = 5; // Saklanacak Geçmiş Çizim Sayısı //================================================================== // BÖLÜM 3: GLOBAL DEĞİŞKENLER & SABİTLER //================================================================== ENUM_CHART_MODE enumChartMode = WRONG_VALUE; color clrChartLine = WRONG_VALUE; double dblEMAWeight, dblEMAComplement; //--- Bufferlar double dblBufferOpen[], dblBufferHigh[], dblBufferLow[], dblBufferClose[]; double dblBufferEMA[], dblBufferDEMA[], dblBufferZEMA[]; #ifdef __MQL5__ double dblBufferColour[]; #endif //--- Sekans Takip Değişkenleri int g_current_sequence_color = -1; string g_current_line_name = ""; int g_sequence_id = 0; //--- Renk Sabitleri (Bright / Dim) color clrBullBright = clrLimeGreen; color clrBullDim = clrForestGreen; // Kapanan boğa sekansı rengi color clrBearBright = clrFireBrick; color clrBearDim = clrMaroon; // Kapanan ayı sekansı rengi //+------------------------------------------------------------------+ //| Başlatma Fonksiyonu | //+------------------------------------------------------------------+ int OnInit(void) { // Input Validation [cite: 46] if(dblPeriod <= 1.0) return(INIT_PARAMETERS_INCORRECT); if(HistoryDepth < 1) return(INIT_PARAMETERS_INCORRECT); dblEMAWeight = 2.0 / (dblPeriod + 1.0); dblEMAComplement = 1.0 - dblEMAWeight; if(boolLineGraph) { enumChartMode = (ENUM_CHART_MODE)ChartGetInteger(0, CHART_MODE); ChartSetInteger(0, CHART_MODE, CHART_LINE); if(boolHideLine) { clrChartLine = (color)ChartGetInteger(0, CHART_COLOR_CHART_LINE); ChartSetInteger(0, CHART_COLOR_CHART_LINE, clrNONE); } } IndicatorSetInteger(INDICATOR_DIGITS, _Digits); #ifdef __MQL5__ SetIndexBuffer(0, dblBufferOpen, INDICATOR_DATA); SetIndexBuffer(1, dblBufferHigh, INDICATOR_DATA); SetIndexBuffer(2, dblBufferLow, INDICATOR_DATA); SetIndexBuffer(3, dblBufferClose, INDICATOR_DATA); SetIndexBuffer(4, dblBufferColour, INDICATOR_COLOR_INDEX); SetIndexBuffer(5, dblBufferEMA, INDICATOR_CALCULATIONS); if(boolZeroLag) { SetIndexBuffer(6, dblBufferDEMA, INDICATOR_CALCULATIONS); SetIndexBuffer(7, dblBufferZEMA, INDICATOR_CALCULATIONS); } ArraySetAsSeries(dblBufferColour, true); #endif ArraySetAsSeries(dblBufferOpen, true); ArraySetAsSeries(dblBufferHigh, true); ArraySetAsSeries(dblBufferLow, true); ArraySetAsSeries(dblBufferClose, true); ArraySetAsSeries(dblBufferEMA, true); if(boolZeroLag) { ArraySetAsSeries(dblBufferDEMA, true); ArraySetAsSeries(dblBufferZEMA, true); } IndicatorSetString(INDICATOR_SHORTNAME, _NAME_ + (boolZeroLag ? "(Z" : "(") + DoubleToString(dblPeriod, 3) + ")"); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Deinit Fonksiyonu | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(boolLineGraph && ((int)enumChartMode != WRONG_VALUE)) ChartSetInteger(0, CHART_MODE, enumChartMode); if(boolHideLine && ((int)clrChartLine != WRONG_VALUE)) ChartSetInteger(0, CHART_COLOR_CHART_LINE, clrChartLine); // Oluşturulan tüm çizgileri temizle ObjectsDeleteAll(0, "HA_line_"); } //+------------------------------------------------------------------+ //| Ana Hesaplama Döngüsü | //+------------------------------------------------------------------+ 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[]) { if(rates_total < 2) return 0; int intPrevCalc = prev_calculated; ArraySetAsSeries(open, true); ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(close, true); ArraySetAsSeries(time, true); //--- Değişkenler bool boolUpCandle, boolDownCandle; double dblClose, dblEMA, dblDEMA = 0, dblZEMA = 0; double dblClosePrevious, dblEMAPrevious, dblDEMAPrevious; double dblOpen = EMPTY_VALUE, dblLow, dblHigh; int intMax = rates_total - 1; int intLimit = rates_total - ((intPrevCalc < 1) ? 1 : intPrevCalc); int intIndex = intLimit; int intIndexPrev = intIndex + 1; //--- Heikin Ashi Hesaplama for(; intIndex >= 0; intIndex--, intIndexPrev--) { dblLow = low[intIndex]; dblHigh = high[intIndex]; dblBufferClose[intIndex] = dblClose = NormalizeDouble((open[intIndex] + dblHigh + dblLow + close[intIndex]) * 0.25, _Digits); if(intIndex < intMax) { dblClosePrevious = dblBufferClose[intIndexPrev]; dblEMAPrevious = dblBufferEMA[intIndexPrev]; dblOpen = dblEMA = dblEMAPrevious + (dblClosePrevious - dblEMAPrevious) * dblEMAWeight; if(boolZeroLag) { dblDEMAPrevious = dblBufferDEMA[intIndexPrev]; dblBufferDEMA[intIndex] = dblDEMA = dblDEMAPrevious + (dblEMA - dblDEMAPrevious) * dblEMAWeight; dblBufferZEMA[intIndex] = dblOpen = dblZEMA = dblEMA * 2 - dblDEMA; } dblLow = fmin(fmin(dblLow, dblOpen), dblClose); dblHigh = fmax(fmax(dblHigh, dblOpen), dblClose); } else { dblOpen = dblEMA = open[intIndex] + (close[intIndex] - open[intIndex]) * dblEMAWeight; dblBufferEMA[intIndex] = dblEMA; } dblBufferEMA[intIndex] = dblEMA; if(boolZeroLag) { dblBufferDEMA[intIndex] = dblDEMA; dblBufferZEMA[intIndex] = dblZEMA; } dblBufferOpen[intIndex] = dblOpen = NormalizeDouble(dblOpen, _Digits); boolUpCandle = dblOpen < dblClose; boolDownCandle = dblOpen > dblClose; #ifdef __MQL5__ dblBufferLow[intIndex] = dblLow; dblBufferHigh[intIndex] = dblHigh; dblBufferColour[intIndex] = boolUpCandle ? 0 : (boolDownCandle ? 1 : 2); #endif } //================================================================== // ÇİZİM YÖNETİMİ (Revize Edildi: V1.50) //================================================================== int curr_color_idx = (int)dblBufferColour[0]; if(curr_color_idx != 0 && curr_color_idx != 1) return rates_total; bool is_bull = (curr_color_idx == 0); color active_color = is_bull ? clrBullBright : clrBearBright; double line_price = NormalizeDouble(is_bull ? dblBufferLow[0] : dblBufferHigh[0], _Digits); datetime start_time = time[0]; long bar_duration = PeriodSeconds(_Period); datetime visual_end_time = (datetime)((long)start_time + 3 * bar_duration); // Çizginin geleceğe uzanması // 1. Yeni Sekans Kontrolü bool new_sequence = (g_current_sequence_color != curr_color_idx); if(new_sequence) { // A) Önceki Sekansı Kapat (Rengi Koyulaştır) if(g_current_line_name != "") { bool prev_was_bull = (g_current_sequence_color == 0); color dim_color = prev_was_bull ? clrBullDim : clrBearDim; if(ObjectFind(0, g_current_line_name) >= 0) { ObjectSetInteger(0, g_current_line_name, OBJPROP_COLOR, dim_color); ObjectSetInteger(0, g_current_line_name, OBJPROP_WIDTH, 1); // İsteğe bağlı inceltme } } // B) Yeni ID ve İsim Oluştur g_current_sequence_color = curr_color_idx; g_sequence_id++; g_current_line_name = "HA_line_" + IntegerToString(g_sequence_id); // C) Eski Çizimleri Temizle (Limit Kontrolü) // Eğer limit 5 ise, ID'si (Current - 5) olanı sil. int id_to_delete = g_sequence_id - HistoryDepth; string name_to_delete = "HA_line_" + IntegerToString(id_to_delete); ObjectDelete(0, name_to_delete); } // 2. Aktif (Canlı) Çizgiyi Yönet // Eğer çizgi yoksa oluştur, varsa güncelle if(ObjectFind(0, g_current_line_name) < 0) { ObjectCreate(0, g_current_line_name, OBJ_TREND, 0, start_time, line_price, visual_end_time, line_price); ObjectSetInteger(0, g_current_line_name, OBJPROP_COLOR, active_color); ObjectSetInteger(0, g_current_line_name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, g_current_line_name, OBJPROP_WIDTH, 2); // Aktif çizgi daha kalın ObjectSetInteger(0, g_current_line_name, OBJPROP_RAY_RIGHT, false); ObjectSetInteger(0, g_current_line_name, OBJPROP_BACK, false); ObjectSetInteger(0, g_current_line_name, OBJPROP_SELECTABLE, false); } else { // Sadece aktif çizginin pozisyonunu güncelle (fiyat değişirse) // Not: Eski çizgiler (dim olanlar) güncellenmez, oldukları yerde kalırlar. ObjectMove(0, g_current_line_name, 0, start_time, line_price); ObjectMove(0, g_current_line_name, 1, visual_end_time, line_price); // Renk tekrar bright yapılmalı (eğer manuel değişirse diye) ObjectSetInteger(0, g_current_line_name, OBJPROP_COLOR, active_color); } return(rates_total); }