From 754442759c188b068b5d052292a2f0bf4fe4a2cf Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Mon, 1 Sep 2025 21:08:10 +0200 Subject: [PATCH] new files added --- .../MyIndicators/Murrey_Math_Line_X.mq5 | 560 ++++++++++++++++++ 1 file changed, 560 insertions(+) create mode 100644 Indicators/MyIndicators/Murrey_Math_Line_X.mq5 diff --git a/Indicators/MyIndicators/Murrey_Math_Line_X.mq5 b/Indicators/MyIndicators/Murrey_Math_Line_X.mq5 new file mode 100644 index 0000000..4ed2fbc --- /dev/null +++ b/Indicators/MyIndicators/Murrey_Math_Line_X.mq5 @@ -0,0 +1,560 @@ +//+------------------------------------------------------------------+ +//| Murrey_Math_Line_X.mq5 | +//| Copyright 2025, xxxxxxxx| +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property version "2.40" +#property description "A clean, self-contained, object-oriented Murrey Math Lines indicator with MTF support." + +#property indicator_chart_window +#property indicator_plots 0 + +//+------------------------------------------------------------------+ +//| CLASS: CMurreyMathCalculator | +//| Handles the core MTF calculation for Murrey Math levels. | +//+------------------------------------------------------------------+ +class CMurreyMathCalculator + { +private: + string m_symbol; + ENUM_TIMEFRAMES m_timeframe; + int m_period; + int m_step_back; + +public: + CMurreyMathCalculator(string symbol, ENUM_TIMEFRAMES timeframe, int period, int step_back); + ~CMurreyMathCalculator(void) {}; + + bool CalculateLevels(double &levels[]); + }; + +//+------------------------------------------------------------------+ +//| CMurreyMathCalculator: Constructor | +//+------------------------------------------------------------------+ +CMurreyMathCalculator::CMurreyMathCalculator(string symbol, ENUM_TIMEFRAMES timeframe, int period, int step_back) : + m_symbol(symbol), m_timeframe(timeframe), m_period(period), m_step_back(step_back) + { + } + +//+------------------------------------------------------------------+ +//| CMurreyMathCalculator: The core MTF calculation algorithm | +//+------------------------------------------------------------------+ +bool CMurreyMathCalculator::CalculateLevels(double &levels[]) + { + int bars_to_copy = m_period + m_step_back; + if(bars_to_copy <= 0) + bars_to_copy = 1; + + double htf_high[], htf_low[]; + + int copied_high = CopyHigh(m_symbol, m_timeframe, 0, bars_to_copy, htf_high); + int copied_low = CopyLow(m_symbol, m_timeframe, 0, bars_to_copy, htf_low); + + if(copied_high < bars_to_copy || copied_low < bars_to_copy) + { + Print("Error: Not enough history on ", EnumToString(m_timeframe), " to calculate Murrey Math."); + return false; + } + + ArraySetAsSeries(htf_high, false); + ArraySetAsSeries(htf_low, false); + + int rates_total = ArraySize(htf_high); + int start_pos = rates_total - 1 - m_step_back; + + int min_idx = ArrayMinimum(htf_low, start_pos - m_period + 1, m_period); + int max_idx = ArrayMaximum(htf_high, start_pos - m_period + 1, m_period); + + double v1 = htf_low[min_idx]; + double v2 = htf_high[max_idx]; + + double fractal = 0; + if((v2 <= 250000) && (v2 > 25000)) + fractal = 100000; + else + if((v2 <= 25000) && (v2 > 2500)) + fractal = 10000; + else + if((v2 <= 2500) && (v2 > 250)) + fractal = 1000; + else + if((v2 <= 250) && (v2 > 25)) + fractal = 100; + else + if((v2 <= 25) && (v2 > 12.5)) + fractal = 12.5; + else + if((v2 <= 12.5) && (v2 > 6.25)) + fractal = 12.5; + else + if((v2 <= 6.25) && (v2 > 3.125)) + fractal = 6.25; + else + if((v2 <= 3.125) && (v2 > 1.5625)) + fractal = 3.125; + else + if((v2 <= 1.5625) && (v2 > 0.390625)) + fractal = 1.5625; + else + if((v2 <= 0.390625) && (v2 > 0)) + fractal = 0.1953125; + + if(fractal == 0) + return false; + + double range = v2 - v1; + if(range <= 0) + return false; + + double sum = MathFloor(MathLog(fractal / range) / MathLog(2)); + double octave = fractal * (MathPow(0.5, sum)); + double mn = MathFloor(v1 / octave) * octave; + double mx; + if(mn + octave > v2) + mx = mn + octave; + else + mx = mn + (2 * octave); + + double x1=0, x2=0, x3=0, x4=0, x5=0, x6=0; + if((v1 >= (3 * (mx - mn) / 16 + mn)) && (v2 <= (9 * (mx - mn) / 16 + mn))) + x2 = mn + (mx - mn) / 2; + if((v1 >= (mn - (mx - mn) / 8)) && (v2 <= (5 * (mx - mn) / 8 + mn)) && (x2 == 0)) + x1 = mn + (mx - mn) / 2; + if((v1 >= (mn + 7 * (mx - mn) / 16)) && (v2 <= (13 * (mx - mn) / 16 + mn))) + x4 = mn + 3 * (mx - mn) / 4; + if((v1 >= (mn + 3 * (mx - mn) / 8)) && (v2 <= (9 * (mx - mn) / 8 + mn)) && (x4 == 0)) + x5 = mx; + if((v1 >= (mn + (mx - mn) / 8)) && (v2 <= (7 * (mx - mn) / 8 + mn)) && (x1 == 0) && (x2 == 0) && (x4 == 0) && (x5 == 0)) + x3 = mn + 3 * (mx - mn) / 4; + if((x1 + x2 + x3 + x4 + x5) == 0) + x6 = mx; + double finalH = x1 + x2 + x3 + x4 + x5 + x6; + + double y1=0, y2=0, y3=0, y4=0, y5=0, y6=0; + if(x1 > 0) + y1 = mn; + if(x2 > 0) + y2 = mn + (mx - mn) / 4; + if(x3 > 0) + y3 = mn + (mx - mn) / 4; + if(x4 > 0) + y4 = mn + (mx - mn) / 2; + if(x5 > 0) + y5 = mn + (mx - mn) / 2; + if((finalH > 0) && ((y1 + y2 + y3 + y4 + y5) == 0)) + y6 = mn; + double finalL = y1 + y2 + y3 + y4 + y5 + y6; + + double dmml = (finalH - finalL) / 8; + if(dmml <= 0) + return false; + + levels[0] = (finalL - dmml * 2); + for(int i = 1; i < 13; i++) + levels[i] = levels[i - 1] + dmml; + + return true; + } + +//+------------------------------------------------------------------+ +//| CLASS: CMurreyMathDrawer | +//| Handles the creation and management of chart objects. | +//+------------------------------------------------------------------+ +class CMurreyMathDrawer + { +private: + long m_chart_id; + string m_prefix; + string m_font_face; + int m_font_size; + bool m_label_side_right; + + color m_colors[13]; + int m_widths[13]; + string m_line_text[13]; + + void CreateOrMoveHLine(int index, double price); + void CreateOrMoveText(int index, datetime time, double price); + +public: + CMurreyMathDrawer(string prefix, string font, int size, bool right_side); + ~CMurreyMathDrawer(void); + + void SetLineStyles(const color &colors[], const int &widths[]); + void DrawLevels(const datetime &time[], const double &levels[]); + }; + +//+------------------------------------------------------------------+ +//| CMurreyMathDrawer: Constructor | +//+------------------------------------------------------------------+ +CMurreyMathDrawer::CMurreyMathDrawer(string prefix, string font, int size, bool right_side) : + m_prefix(prefix), m_font_face(font), m_font_size(size), m_label_side_right(right_side) + { + m_chart_id = ChartID(); + + m_line_text[0] = "[-2/8]P Extreme Overshoot"; + m_line_text[1] = "[-1/8]P Overshoot"; + m_line_text[2] = "[0/8]P Ultimate Support"; + m_line_text[3] = "[1/8]P Weak, Stop & Reverse"; + m_line_text[4] = "[2/8]P Pivot, Reverse"; + m_line_text[5] = "[3/8]P Bottom of Trading Range"; + m_line_text[6] = "[4/8]P Major S/R Pivot"; + m_line_text[7] = "[5/8]P Top of Trading Range"; + m_line_text[8] = "[6/8]P Pivot, Reverse"; + m_line_text[9] = "[7/8]P Weak, Stop & Reverse"; + m_line_text[10] = "[8/8]P Ultimate Resistance"; + m_line_text[11] = "[+1/8]P Overshoot"; + m_line_text[12] = "[+2/8]P Extreme Overshoot"; + } + +//+------------------------------------------------------------------+ +//| CMurreyMathDrawer: Destructor (cleans up objects) | +//+------------------------------------------------------------------+ +CMurreyMathDrawer::~CMurreyMathDrawer(void) + { + ObjectsDeleteAll(m_chart_id, m_prefix); + } + +//+------------------------------------------------------------------+ +//| CMurreyMathDrawer: Set line styles | +//+------------------------------------------------------------------+ +void CMurreyMathDrawer::SetLineStyles(const color &colors[], const int &widths[]) + { + ArrayCopy(m_colors, colors); + ArrayCopy(m_widths, widths); + } + +//+------------------------------------------------------------------+ +//| CMurreyMathDrawer: Main drawing method | +//+------------------------------------------------------------------+ +void CMurreyMathDrawer::DrawLevels(const datetime &time[], const double &levels[]) + { + int rates_total = ArraySize(time); + if(rates_total < 2) + return; + + int first_bar_idx = (int)ChartGetInteger(m_chart_id, CHART_FIRST_VISIBLE_BAR, 0); + + if(m_label_side_right) + { + first_bar_idx = 1; + } + + if(first_bar_idx < 1 || first_bar_idx >= rates_total) + return; + + datetime label_time = time[first_bar_idx - 1]; + + for(int i = 0; i < 13; i++) + { + CreateOrMoveHLine(i, levels[i]); + CreateOrMoveText(i, label_time, levels[i]); + } + } + +//+------------------------------------------------------------------+ +//| CMurreyMathDrawer: Helper to draw horizontal lines | +//+------------------------------------------------------------------+ +void CMurreyMathDrawer::CreateOrMoveHLine(int index, double price) + { + string name = m_prefix + "line_" + (string)index; + if(ObjectFind(m_chart_id, name) < 0) + { + ObjectCreate(m_chart_id, name, OBJ_HLINE, 0, 0, price); + ObjectSetInteger(m_chart_id, name, OBJPROP_STYLE, STYLE_SOLID); + ObjectSetInteger(m_chart_id, name, OBJPROP_COLOR, m_colors[index]); + ObjectSetInteger(m_chart_id, name, OBJPROP_WIDTH, m_widths[index]); + ObjectSetInteger(m_chart_id, name, OBJPROP_BACK, true); + } + else + { + ObjectMove(m_chart_id, name, 0, 0, price); + ObjectSetInteger(m_chart_id, name, OBJPROP_COLOR, m_colors[index]); + ObjectSetInteger(m_chart_id, name, OBJPROP_WIDTH, m_widths[index]); + } + } + +//+------------------------------------------------------------------+ +//| CMurreyMathDrawer: Helper to draw text labels | +//+------------------------------------------------------------------+ +void CMurreyMathDrawer::CreateOrMoveText(int index, datetime time, double price) + { + string name = m_prefix + "text_" + (string)index; + ENUM_ANCHOR_POINT anchor = ANCHOR_LEFT_UPPER; + + if(ObjectFind(m_chart_id, name) < 0) + { + ObjectCreate(m_chart_id, name, OBJ_TEXT, 0, time, price); + ObjectSetString(m_chart_id, name, OBJPROP_TEXT, m_line_text[index]); + ObjectSetInteger(m_chart_id, name, OBJPROP_FONTSIZE, m_font_size); + ObjectSetString(m_chart_id, name, OBJPROP_FONT, m_font_face); + ObjectSetInteger(m_chart_id, name, OBJPROP_COLOR, m_colors[index]); + ObjectSetInteger(m_chart_id, name, OBJPROP_ANCHOR, anchor); + } + else + { + ObjectMove(m_chart_id, name, 0, time, price); + ObjectSetInteger(m_chart_id, name, OBJPROP_COLOR, m_colors[index]); + } + } + +//+------------------------------------------------------------------+ +//| CLASS: CMurreyMathController | +//| The main controller class that manages all components. | +//+------------------------------------------------------------------+ +class CMurreyMathController + { +private: + CMurreyMathCalculator *m_calculator; + CMurreyMathDrawer *m_drawer; + + double m_mml_levels[13]; + +public: + CMurreyMathController(void); + ~CMurreyMathController(void); + + bool Initialize(ENUM_TIMEFRAMES timeframe, int period, int stepBack, bool labelSideRight, + string fontFace, int fontSize, string prefix); + + void SetLineStyles(const color &colors[], const int &widths[]); + + void Update(const datetime &time[]); + }; + +//+------------------------------------------------------------------+ +//| CMurreyMathController: Constructor | +//+------------------------------------------------------------------+ +CMurreyMathController::CMurreyMathController(void) : m_calculator(NULL), m_drawer(NULL) + { + ArrayInitialize(m_mml_levels, 0.0); + } + +//+------------------------------------------------------------------+ +//| CMurreyMathController: Destructor | +//+------------------------------------------------------------------+ +CMurreyMathController::~CMurreyMathController(void) + { + if(CheckPointer(m_calculator) != POINTER_INVALID) + delete m_calculator; + if(CheckPointer(m_drawer) != POINTER_INVALID) + delete m_drawer; + } + +//+------------------------------------------------------------------+ +//| CMurreyMathController: Initialize all components | +//+------------------------------------------------------------------+ +bool CMurreyMathController::Initialize(ENUM_TIMEFRAMES timeframe, int period, int stepBack, bool labelSideRight, + string fontFace, int fontSize, string prefix) + { + m_calculator = new CMurreyMathCalculator(_Symbol, timeframe, period, stepBack); + m_drawer = new CMurreyMathDrawer(prefix, fontFace, fontSize, labelSideRight); + + if(CheckPointer(m_calculator) == POINTER_INVALID || CheckPointer(m_drawer) == POINTER_INVALID) + { + Print("Failed to initialize Murrey Math components."); + return false; + } + + return true; + } + +//+------------------------------------------------------------------+ +//| CMurreyMathController: Set line styles for the drawer | +//+------------------------------------------------------------------+ +void CMurreyMathController::SetLineStyles(const color &colors[], const int &widths[]) + { + if(CheckPointer(m_drawer) != POINTER_INVALID) + m_drawer.SetLineStyles(colors, widths); + } + +//+------------------------------------------------------------------+ +//| CMurreyMathController: Main update method | +//+------------------------------------------------------------------+ +void CMurreyMathController::Update(const datetime &time[]) + { +//--- Calculation and drawing are now a single, atomic operation + if(m_calculator.CalculateLevels(m_mml_levels)) + { + m_drawer.DrawLevels(time, m_mml_levels); + } + } + +//--- Indicator Input Parameters --- +input int InpPeriod = 64; // Period for High/Low lookup on the selected timeframe +input ENUM_TIMEFRAMES InpUpperTimeframe = PERIOD_H4; // Timeframe for calculation (0 = Current) +input int InpStepBack = 0; // Bar to start calculation from + +enum enum_side { Left, Right }; +input enum_side InpLabelSide = Left; + +input group "Line Colors" +input color InpClr_m2_8 = clrSilver; +input color InpClr_m1_8 = clrSilver; +input color InpClr_0_8 = clrSilver; +input color InpClr_1_8 = clrSilver; +input color InpClr_2_8 = clrSilver; +input color InpClr_3_8 = clrSilver; +input color InpClr_4_8 = clrSilver; +input color InpClr_5_8 = clrSilver; +input color InpClr_6_8 = clrSilver; +input color InpClr_7_8 = clrSilver; +input color InpClr_8_8 = clrSilver; +input color InpClr_p1_8 = clrSilver; +input color InpClr_p2_8 = clrSilver; + +input group "Line Widths" +input int InpWdth_m2_8 = 1; +input int InpWdth_m1_8 = 1; +input int InpWdth_0_8 = 1; +input int InpWdth_1_8 = 1; +input int InpWdth_2_8 = 1; +input int InpWdth_3_8 = 1; +input int InpWdth_4_8 = 1; +input int InpWdth_5_8 = 1; +input int InpWdth_6_8 = 1; +input int InpWdth_7_8 = 1; +input int InpWdth_8_8 = 1; +input int InpWdth_p1_8 = 1; +input int InpWdth_p2_8 = 1; + +input group "Labels" +input string InpFontFace = "Verdana"; +input int InpFontSize = 10; +input string InpObjectPrefix = "MML-"; + +//--- Global controller object --- +CMurreyMathController *g_murreyMath; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + g_murreyMath = new CMurreyMathController(); + if(CheckPointer(g_murreyMath) == POINTER_INVALID) + { + Print("Error creating CMurreyMathController object."); + return(INIT_FAILED); + } + + ENUM_TIMEFRAMES calc_timeframe = (InpUpperTimeframe == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : InpUpperTimeframe; + + if(!g_murreyMath.Initialize( + calc_timeframe, + InpPeriod, + InpStepBack, + (InpLabelSide == Right), + InpFontFace, + InpFontSize, + InpObjectPrefix + )) + { + return(INIT_FAILED); + } + + color colors[13]; + int widths[13]; + + colors[0] = InpClr_m2_8; + widths[0] = InpWdth_m2_8; + colors[1] = InpClr_m1_8; + widths[1] = InpWdth_m1_8; + colors[2] = InpClr_0_8; + widths[2] = InpWdth_0_8; + colors[3] = InpClr_1_8; + widths[3] = InpWdth_1_8; + colors[4] = InpClr_2_8; + widths[4] = InpWdth_2_8; + colors[5] = InpClr_3_8; + widths[5] = InpWdth_3_8; + colors[6] = InpClr_4_8; + widths[6] = InpWdth_4_8; + colors[7] = InpClr_5_8; + widths[7] = InpWdth_5_8; + colors[8] = InpClr_6_8; + widths[8] = InpWdth_6_8; + colors[9] = InpClr_7_8; + widths[9] = InpWdth_7_8; + colors[10] = InpClr_8_8; + widths[10] = InpWdth_8_8; + colors[11] = InpClr_p1_8; + widths[11] = InpWdth_p1_8; + colors[12] = InpClr_p2_8; + widths[12] = InpWdth_p2_8; + + g_murreyMath.SetLineStyles(colors, widths); + + return(INIT_SUCCEEDED); + } + +//+------------------------------------------------------------------+ +//| Custom indicator deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { + if(CheckPointer(g_murreyMath) != POINTER_INVALID) + delete g_murreyMath; + } + +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +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[]) + { +//--- For drawing logic, we MUST use a timeseries array to replicate the original code's behavior + ArraySetAsSeries(time, true); + + ENUM_TIMEFRAMES calc_timeframe = (InpUpperTimeframe == PERIOD_CURRENT) ? (ENUM_TIMEFRAMES)Period() : InpUpperTimeframe; + + static datetime last_htf_bar_time = 0; + datetime htf_time[]; + + bool new_htf_bar = false; + if(CopyTime(_Symbol, calc_timeframe, 0, 1, htf_time) > 0) + { + if(htf_time[0] > last_htf_bar_time) + { + last_htf_bar_time = htf_time[0]; + new_htf_bar = true; + } + } + +//--- Recalculate on a new higher timeframe bar OR on the very first run + if(new_htf_bar || prev_calculated == 0) + { + if(CheckPointer(g_murreyMath) != POINTER_INVALID) + { + g_murreyMath.Update(time); + } + } +//--- On chart scroll, we need to reposition the labels + else + { + static int last_first_visible_bar = -1; + int current_first_visible_bar = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR, 0); + if(current_first_visible_bar != last_first_visible_bar) + { + if(CheckPointer(g_murreyMath) != POINTER_INVALID) + { + //--- We don't need to recalculate, just redraw the objects + g_murreyMath.Update(time); + } + last_first_visible_bar = current_first_visible_bar; + } + } + + return(rates_total); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+