//+-------------------------------------------------------\!/--------------------------------------------------------+ //| MA-200 & Gann MA-HL Indicator - TRUE GANN METHOD with MTF | //+-------------------------------------------------------------------------------------------------------------------+ #property description "Dual Moving Average System: MA-200 and TRUE Gann High/Low MA" #property version "1.30" #property copyright "Authentic Gann HiLo Activator Logic with MTF" #property indicator_chart_window #property indicator_buffers 9 #property indicator_plots 3 //--- Plot 1: Colored Candles #property indicator_label1 "Colored Candles" #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_color1 C'62,62,62', C'109,188,235', C'255,0,110' // Neutral, Blue Up, Red Down #property indicator_width1 1 //--- Plot 2: MA-HL (Gann High/Low) #property indicator_label2 "MA-HL (Gann)" #property indicator_type2 DRAW_COLOR_LINE #property indicator_color2 clrDodgerBlue, clrOrangeRed #property indicator_style2 STYLE_SOLID #property indicator_width2 3 //--- Plot 3: MA-200 #property indicator_label3 "MA-200" #property indicator_type3 DRAW_COLOR_LINE #property indicator_color3 clrLimeGreen, clrOrange #property indicator_style3 STYLE_SOLID #property indicator_width3 4 //+------------------------------------------------------------------------------------------------------------------+ //| INPUT PARAMETERS | //+------------------------------------------------------------------------------------------------------------------+ input group "=== Multi-Timeframe Settings ===" input ENUM_TIMEFRAMES MTF_Timeframe = PERIOD_CURRENT; // Timeframe for calculation input bool MTF_Interpolate = true; // Interpolate MTF lines input group "=== Moving Average Settings ===" input int MA_HL_Period = 10; // MA-HL Period (Gann R value) input int MA_200_Period = 200; // MA-200 Period input ENUM_MA_METHOD MA_Method = MODE_LWMA; // MA Method (Gann uses LWMA) input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // Applied Price for MA-200 input group "=== Display Settings ===" input bool CandleColorwithMA200 = true; // Candle coloring with MA-200 filter input group "=== Header Settings ===" input bool ShowSymbolHeader = true; // Show symbol header input int HeaderLR = 177; // Header left-right offset input int HeaderUD = 1; // Header up-down offset input int HeaderSize = 40; // Header font size input color HeaderBackground = C'50,60,70'; // Header background color input group "=== Debug ===" input bool DebugWithSquealers = false; // Enable debug logging //+------------------------------------------------------------------------------------------------------------------+ //| GLOBAL VARIABLES | //+------------------------------------------------------------------------------------------------------------------+ long chartID; string MyName = "MA-200 & Gann MA-HL"; ENUM_TIMEFRAMES CalcTimeframe; // Buffers double buf_open[], buf_high[], buf_low[], buf_close[], buf_color[]; double buf_ma_hl[], buf_ma_hl_color[]; double buf_ma200[], buf_ma200_color[]; // Handles int handle_ma_hl_high, handle_ma_hl_low, handle_ma200; // Object names string SymbolHeaderTextObj = "SymbolHeaderText"; string SymbolHeaderTextShadowObj = "SymbolHeaderTextShadow"; //+------------------------------------------------------------------------------------------------------------------+ int OnInit() { if (DebugWithSquealers) Print("=== OnInit Start ==="); chartID = ChartID(); CalcTimeframe = (MTF_Timeframe == PERIOD_CURRENT) ? _Period : MTF_Timeframe; if (MA_HL_Period < 1 || MA_200_Period < 1) { Print("ERROR: Invalid MA periods"); return INIT_PARAMETERS_INCORRECT; } if (CalcTimeframe < _Period) { Print("ERROR: Cannot use lower timeframe than chart"); return INIT_PARAMETERS_INCORRECT; } // Set as series for proper indexing ArraySetAsSeries(buf_open, true); ArraySetAsSeries(buf_high, true); ArraySetAsSeries(buf_low, true); ArraySetAsSeries(buf_close, true); ArraySetAsSeries(buf_color, true); ArraySetAsSeries(buf_ma_hl, true); ArraySetAsSeries(buf_ma_hl_color, true); ArraySetAsSeries(buf_ma200, true); ArraySetAsSeries(buf_ma200_color, true); // Bind buffers SetIndexBuffer(0, buf_open, INDICATOR_DATA); SetIndexBuffer(1, buf_high, INDICATOR_DATA); SetIndexBuffer(2, buf_low, INDICATOR_DATA); SetIndexBuffer(3, buf_close, INDICATOR_DATA); SetIndexBuffer(4, buf_color, INDICATOR_COLOR_INDEX); SetIndexBuffer(5, buf_ma_hl, INDICATOR_DATA); SetIndexBuffer(6, buf_ma_hl_color, INDICATOR_COLOR_INDEX); SetIndexBuffer(7, buf_ma200, INDICATOR_DATA); SetIndexBuffer(8, buf_ma200_color, INDICATOR_COLOR_INDEX); // Set empty values PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0); PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, 0); // Create MA handles handle_ma_hl_high = iMA(_Symbol, CalcTimeframe, MA_HL_Period, 0, MA_Method, PRICE_HIGH); handle_ma_hl_low = iMA(_Symbol, CalcTimeframe, MA_HL_Period, 0, MA_Method, PRICE_LOW); handle_ma200 = iMA(_Symbol, CalcTimeframe, MA_200_Period, 0, MA_Method, MA_Price); if (handle_ma_hl_high == INVALID_HANDLE || handle_ma_hl_low == INVALID_HANDLE || handle_ma200 == INVALID_HANDLE) { Print("ERROR: Failed to create MA handles"); return INIT_FAILED; } if (ShowSymbolHeader) CreateSymbolHeader(); IndicatorSetInteger(INDICATOR_DIGITS, _Digits); string tfString = (CalcTimeframe == _Period) ? "" : " [" + TimeFrameToString(CalcTimeframe) + "]"; IndicatorSetString(INDICATOR_SHORTNAME, MyName + tfString); if (DebugWithSquealers) { Print("Calc TF: ", EnumToString(CalcTimeframe), " | Chart TF: ", EnumToString(_Period)); Print("Interpolate: ", MTF_Interpolate); } return INIT_SUCCEEDED; } //+------------------------------------------------------------------------------------------------------------------+ void OnDeinit(const int reason) { if (DebugWithSquealers) Print("OnDeinit - Reason: ", reason); Comment(""); if (handle_ma_hl_high != INVALID_HANDLE) IndicatorRelease(handle_ma_hl_high); if (handle_ma_hl_low != INVALID_HANDLE) IndicatorRelease(handle_ma_hl_low); if (handle_ma200 != INVALID_HANDLE) IndicatorRelease(handle_ma200); ObjectDelete(0, SymbolHeaderTextObj); ObjectDelete(0, SymbolHeaderTextShadowObj); } //+------------------------------------------------------------------------------------------------------------------+ 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 < MA_200_Period + 1) { if (DebugWithSquealers) Print("Not enough bars: ", rates_total); return 0; } // Set arrays as series to match MT5 convention ArraySetAsSeries(open, true); ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(close, true); ArraySetAsSeries(time, true); int limit = rates_total - prev_calculated; if (prev_calculated > 0) limit++; if (limit > rates_total) limit = rates_total; if (DebugWithSquealers && prev_calculated == 0) { Print("First calculation - limit: ", limit, " rates_total: ", rates_total); } // Copy MA data from calculation timeframe - copy all available bars double ma_hl_high[], ma_hl_low[], ma200[]; int bars_to_copy = rates_total; ArraySetAsSeries(ma_hl_high, true); ArraySetAsSeries(ma_hl_low, true); ArraySetAsSeries(ma200, true); int copied_high = CopyBuffer(handle_ma_hl_high, 0, 0, bars_to_copy, ma_hl_high); int copied_low = CopyBuffer(handle_ma_hl_low, 0, 0, bars_to_copy, ma_hl_low); int copied_200 = CopyBuffer(handle_ma200, 0, 0, bars_to_copy, ma200); if (copied_high <= 0 || copied_low <= 0 || copied_200 <= 0) { if (DebugWithSquealers) { Print("Failed to copy MA buffers - High:", copied_high, " Low:", copied_low, " MA200:", copied_200); } return prev_calculated; } if (DebugWithSquealers && prev_calculated == 0) { Print("Copied buffers - High:", copied_high, " Low:", copied_low, " MA200:", copied_200); Print("Sample values - MA_High[0]=", ma_hl_high[0], " MA_Low[0]=", ma_hl_low[0], " MA200[0]=", ma200[0]); } // Get close prices from calc timeframe for swing calculation double mtf_close[]; ArraySetAsSeries(mtf_close, true); int copied_close = CopyClose(_Symbol, CalcTimeframe, 0, bars_to_copy, mtf_close); if (copied_close <= 0) { if (DebugWithSquealers) Print("Failed to copy close prices - copied:", copied_close); return prev_calculated; } // Calculate swing states int swing[]; ArrayResize(swing, bars_to_copy); ArraySetAsSeries(swing, true); // Initialize oldest bar swing[bars_to_copy - 1] = 0; // Calculate swing from oldest to newest for (int i = bars_to_copy - 2; i >= 0; i--) { if (mtf_close[i] < ma_hl_low[i]) { swing[i] = -1; } else if (mtf_close[i] > ma_hl_high[i]) { swing[i] = 1; } else { swing[i] = swing[i + 1]; } } if (DebugWithSquealers && prev_calculated == 0) { Print("Swing calculation complete - Swing[0]=", swing[0], " Swing[1]=", swing[1]); } // Process chart bars for (int i = limit - 1; i >= 0; i--) { // Copy OHLC to candle buffers buf_open[i] = open[i]; buf_high[i] = high[i]; buf_low[i] = low[i]; buf_close[i] = close[i]; // For current timeframe, swing index = chart bar index if (i >= bars_to_copy) { if (DebugWithSquealers && i < limit - 5) Print("Bar ", i, " out of range"); continue; } int mtf_shift = i; // When same timeframe // If MTF, get the corresponding bar if (CalcTimeframe != _Period) { mtf_shift = iBarShift(_Symbol, CalcTimeframe, time[i]); if (mtf_shift < 0 || mtf_shift >= bars_to_copy) { if (DebugWithSquealers && i < 5) Print("Invalid MTF shift for bar ", i, " shift=", mtf_shift); continue; } } int current_swing = swing[mtf_shift]; // Handle interpolation or direct mapping if (MTF_Interpolate && CalcTimeframe > _Period && mtf_shift < bars_to_copy - 1) { // Get times for interpolation datetime t1 = iTime(_Symbol, CalcTimeframe, mtf_shift); datetime t2 = iTime(_Symbol, CalcTimeframe, mtf_shift + 1); double factor = (t1 == t2) ? 0.0 : (double)(time[i] - t2) / (double)(t1 - t2); factor = MathMax(0.0, MathMin(1.0, factor)); // Interpolate MA values double ma_high_interp = ma_hl_high[mtf_shift + 1] + (ma_hl_high[mtf_shift] - ma_hl_high[mtf_shift + 1]) * factor; double ma_low_interp = ma_hl_low[mtf_shift + 1] + (ma_hl_low[mtf_shift] - ma_hl_low[mtf_shift + 1]) * factor; double ma200_interp = ma200[mtf_shift + 1] + (ma200[mtf_shift] - ma200[mtf_shift + 1]) * factor; if (current_swing == 1) { buf_ma_hl[i] = ma_low_interp; buf_ma_hl_color[i] = 0; } else if (current_swing == -1) { buf_ma_hl[i] = ma_high_interp; buf_ma_hl_color[i] = 1; } else { buf_ma_hl[i] = (ma_high_interp + ma_low_interp) / 2.0; buf_ma_hl_color[i] = 0; } buf_ma200[i] = ma200_interp; } else { // No interpolation - direct values if (current_swing == 1) { buf_ma_hl[i] = ma_hl_low[mtf_shift]; buf_ma_hl_color[i] = 0; } else if (current_swing == -1) { buf_ma_hl[i] = ma_hl_high[mtf_shift]; buf_ma_hl_color[i] = 1; } else { buf_ma_hl[i] = (ma_hl_high[mtf_shift] + ma_hl_low[mtf_shift]) / 2.0; buf_ma_hl_color[i] = 0; } buf_ma200[i] = ma200[mtf_shift]; } // MA-200 color if (mtf_shift < bars_to_copy - 1) { buf_ma200_color[i] = (ma200[mtf_shift] > ma200[mtf_shift + 1]) ? 0 : 1; } else { buf_ma200_color[i] = 0; } // Candle color if (CandleColorwithMA200) { int base = (close[i] > buf_ma200[i]) ? 1 : (close[i] < buf_ma200[i]) ? -1 : 0; int signal = (base == 1 && current_swing == 1) ? 1 : (base == -1 && current_swing == -1) ? -1 : 0; buf_color[i] = (signal == 1) ? 1 : (signal == -1) ? 2 : 0; } else { buf_color[i] = (current_swing == 1) ? 1 : (current_swing == -1) ? 2 : 0; } } UpdateSymbolHeader(); if (DebugWithSquealers) { Print("Calculation complete - Bar[0]: OHLC=", buf_open[0], "/", buf_high[0], "/", buf_low[0], "/", buf_close[0]); Print("Bar[0]: MA-HL=", DoubleToString(buf_ma_hl[0], 5), " MA200=", DoubleToString(buf_ma200[0], 5), " Color=", buf_color[0], " Swing=", swing[0]); } return rates_total; } //+------------------------------------------------------------------------------------------------------------------+ void CreateSymbolHeader() { string symText = _Symbol + " " + TimeFrameToString(_Period); ObjectCreate(0, SymbolHeaderTextShadowObj, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, SymbolHeaderTextShadowObj, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, SymbolHeaderTextShadowObj, OBJPROP_XDISTANCE, HeaderLR + 333); ObjectSetInteger(0, SymbolHeaderTextShadowObj, OBJPROP_YDISTANCE, HeaderUD + 11); ObjectSetString(0, SymbolHeaderTextShadowObj, OBJPROP_TEXT, symText); ObjectSetString(0, SymbolHeaderTextShadowObj, OBJPROP_FONT, "Arial Black"); ObjectSetInteger(0, SymbolHeaderTextShadowObj, OBJPROP_FONTSIZE, HeaderSize); ObjectSetInteger(0, SymbolHeaderTextShadowObj, OBJPROP_COLOR, HeaderBackground); ObjectSetInteger(0, SymbolHeaderTextShadowObj, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER); ObjectSetInteger(0, SymbolHeaderTextShadowObj, OBJPROP_SELECTABLE, false); ObjectCreate(0, SymbolHeaderTextObj, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_XDISTANCE, HeaderLR + 332); ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_YDISTANCE, HeaderUD + 12); ObjectSetString(0, SymbolHeaderTextObj, OBJPROP_TEXT, symText); ObjectSetString(0, SymbolHeaderTextObj, OBJPROP_FONT, "Arial Black"); ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_FONTSIZE, HeaderSize); ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_COLOR, clrSilver); ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER); ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_SELECTABLE, false); } void UpdateSymbolHeader() { if (!ShowSymbolHeader) return; int lastColor = (int)buf_color[0]; color headerColor = (lastColor == 1) ? C'109,188,235' : (lastColor == 2) ? C'255,0,110' : C'62,62,62'; ObjectSetInteger(0, SymbolHeaderTextObj, OBJPROP_COLOR, headerColor); } string TimeFrameToString(int tf) { switch (tf) { case PERIOD_M1: return "M1"; case PERIOD_M5: return "M5"; case PERIOD_M15: return "M15"; case PERIOD_M30: return "M30"; case PERIOD_H1: return "H1"; case PERIOD_H4: return "H4"; case PERIOD_D1: return "D1"; case PERIOD_W1: return "W1"; case PERIOD_MN1: return "MN"; default: return StringFormat("M%d", tf); } }