From b827ff2a38ab18d37f5c4705b6da46179f1f3abc Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Thu, 27 Jun 2024 01:33:54 +0330 Subject: [PATCH] try to complete linear regression ... --- Indicators/x-saherelm.xrl.mq5 | 433 ++++++++++++++++++++++++++++ Libraries/x-saherelm.common.lib.mq5 | 146 ++++++++++ 2 files changed, 579 insertions(+) create mode 100644 Indicators/x-saherelm.xrl.mq5 diff --git a/Indicators/x-saherelm.xrl.mq5 b/Indicators/x-saherelm.xrl.mq5 new file mode 100644 index 00000000..d7689f9e --- /dev/null +++ b/Indicators/x-saherelm.xrl.mq5 @@ -0,0 +1,433 @@ +/////////////////////////////////////////////////////// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------- +// Name: XRL +// Description: Regression Line ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XRL Indicator" +#property strict + +// +#define ShortName "XRL" + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +input group "Market"; +input group "Fast"; +input int fastLength = 9; // Length +input ENUM_APPLIED_PRICE fastAppliedTo = PRICE_CLOSE; // Applied To +input int slowLength = 18; // Length +input ENUM_APPLIED_PRICE slowAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Presentation"; +input bool showFast = true; // Show Fast +input bool showSlow = true; // Show Slow +input bool showVerifier = true; // Show Verifier + +// +// Buffers ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 8 +#property indicator_plots 6 + +// +#define hideColorIDX 0 +#define neuturalColorIDX 1 +#define bullColorIDX 2 +#define bearColorIDX 3 + +// +// Fast ... + +// +#define fastBufferIndex 0 +#define fastBufferPlotIndex 0 +double fastBuffer[]; + +// +#define fastBufferColorIndex 1 +double fastBufferColor[]; + +// +#property indicator_label1 "XRL F" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 CLR_NONE, clrGray, clrAqua, clrMagenta +#property indicator_style1 STYLE_DOT +#property indicator_width1 1 + +// +// Slow ... + +// +#define slowBufferIndex 2 +#define slowBufferPlotIndex 1 +double slowBuffer[]; + +// +#define slowBufferColorIndex 3 +double slowBufferColor[]; + +// +#property indicator_label2 "XRL S" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 CLR_NONE, clrGray, clrAqua, clrMagenta +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +// +// Verifier ... + +// +#define verifierBufferIndex 4 +#define verifierBufferPlotIndex 2 +double verifierBuffer[]; + +// +#define verifierBufferColorIndex 5 +double verifierBufferColor[]; + +// +#property indicator_label3 "XRL V" +#property indicator_type3 DRAW_COLOR_LINE +#property indicator_color3 CLR_NONE, clrGray, clrAqua, clrMagenta +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 + +// +#define fastLRBufferIndex 6 +double fastLRBuffer[]; + +#define slowLRBufferIndex 7 +double slowLRBuffer[]; + +// +// Variables ... + +// +int maxLength = 0; + +// +XLinearRegression fastCalculator; +XLinearRegression slowCalculator; +XLinearRegression verifierCalculator; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + int limit = (prev_calculated > 0) ? prev_calculated - 1 : 0; + + // + // Calculate Verifier ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + double verifierSlope; + double verifierIntercept; + + // + double verifierAppliedPrice = iGetPrice(slowAppliedTo, open[i], high[i], low[i], close[i]); + + // + double verifier = verifierCalculator.Calculate( + verifierAppliedPrice, + slowLength, + verifierSlope, + verifierIntercept, + i, + rates_total // + ); + verifierBuffer[i] = verifier; + + // + double verifierColor = + (i > 0) + ? (verifierBuffer[i] > verifierBuffer[i - 1]) + ? bullColorIDX + : (verifierBuffer[i] < verifierBuffer[i - 1]) + ? bearColorIDX + : verifierBuffer[i - 1] + : neuturalColorIDX; + verifierBufferColor[i] = verifierColor; + } + + // + // Fast ... + + // + // Calculate Fast Intercept and Slope ... + double fastSlope = 0; + double fastIntercept = 0; + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + double fastAppliedPrice = iGetPrice(fastAppliedTo, open[i], high[i], low[i], close[i]); + + // + double fastLRValue = fastCalculator.Calculate( + fastAppliedPrice, + fastLength, + fastSlope, + fastIntercept, + i, + rates_total // + ); + fastLRBuffer[i] = fastLRValue; + } + + // + // Calculate Fast ... + for (int i = 0; i < fastLength && !IsStopped(); i++) + { + // + double fast = fastIntercept + fastSlope * (fastLength - i - 1); + fastBuffer[rates_total - i - 1] = fast; + + // + double fastColor = + (fastSlope > 0) + ? bullColorIDX + : (fastSlope < 0) + ? bearColorIDX + : neuturalColorIDX; + + // + fastBufferColor[rates_total - i - 1] = fastColor; + } + + // + int fastDrawBegin = rates_total - fastLength; + PlotIndexSetInteger(fastBufferIndex, PLOT_DRAW_BEGIN, fastDrawBegin); + + // + // Slow ... + + // + // Calculate Slow Intercept and Slope ... + double slowSlope = 0; + double slowIntercept = 0; + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + double slowAppliedPrice = iGetPrice(slowAppliedTo, open[i], high[i], low[i], close[i]); + + // + double slowLRValue = slowCalculator.Calculate( + slowAppliedPrice, + slowLength, + slowSlope, + slowIntercept, + i, + rates_total // + ); + slowLRBuffer[i] = slowLRValue; + } + + // + // Calculate Slow ... + for (int i = 0; i < slowLength && !IsStopped(); i++) + { + // + double slow = slowIntercept + slowSlope * (slowLength - i - 1); + slowBuffer[rates_total - i - 1] = slow; + + // + double slowColor = + (slowSlope > 0) + ? bullColorIDX + : (slowSlope < 0) + ? bearColorIDX + : neuturalColorIDX; + + // + slowBufferColor[rates_total - i - 1] = slowColor; + } + + // + int slowDrawBegin = rates_total - slowLength; + PlotIndexSetInteger(slowBufferIndex, PLOT_DRAW_BEGIN, slowDrawBegin); + + // + return rates_total; +} + +// +// Custom Functions ... + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + result = fastLength >= 2 && + slowLength > fastLength; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // Ichimoku ... + result = MathMax(fastLength, slowLength); + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // Fast ... + + // + ENUM_DRAW_TYPE fastDrawType = showFast ? DRAW_COLOR_LINE : DRAW_NONE; + + // + SetIndexBuffer(fastBufferIndex, fastBuffer, INDICATOR_DATA); + SetIndexBuffer(fastBufferColorIndex, fastBufferColor, INDICATOR_COLOR_INDEX); + + // + PlotIndexSetInteger(fastBufferIndex, PLOT_SHOW_DATA, showFast); + PlotIndexSetInteger(fastBufferIndex, PLOT_DRAW_TYPE, fastDrawType); + + // + // Slow ... + + // + ENUM_DRAW_TYPE slowDrawType = showSlow ? DRAW_COLOR_LINE : DRAW_NONE; + + // + SetIndexBuffer(slowBufferIndex, slowBuffer, INDICATOR_DATA); + SetIndexBuffer(slowBufferColorIndex, slowBufferColor, INDICATOR_COLOR_INDEX); + + // + PlotIndexSetInteger(slowBufferIndex, PLOT_SHOW_DATA, showSlow); + PlotIndexSetInteger(slowBufferIndex, PLOT_DRAW_TYPE, slowDrawType); + + // + // Verifier ... + + // + ENUM_DRAW_TYPE verifierDrawType = showVerifier ? DRAW_COLOR_LINE : DRAW_NONE; + + // + SetIndexBuffer(verifierBufferIndex, verifierBuffer, INDICATOR_DATA); + SetIndexBuffer(verifierBufferColorIndex, verifierBufferColor, INDICATOR_COLOR_INDEX); + + // + PlotIndexSetInteger(verifierBufferIndex, PLOT_SHOW_DATA, showVerifier); + PlotIndexSetInteger(verifierBufferIndex, PLOT_DRAW_TYPE, verifierDrawType); + + // + // Data Buffers ... + + // + SetIndexBuffer(fastLRBufferIndex, fastLRBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(slowLRBufferIndex, slowLRBuffer, INDICATOR_CALCULATIONS); +} + +// \ No newline at end of file diff --git a/Libraries/x-saherelm.common.lib.mq5 b/Libraries/x-saherelm.common.lib.mq5 index c376b4b6..f8d36ab3 100644 --- a/Libraries/x-saherelm.common.lib.mq5 +++ b/Libraries/x-saherelm.common.lib.mq5 @@ -3372,6 +3372,120 @@ struct XMarketCycle } }; +// +// Linear Regression ... + +// +struct XLinearRegressionWorkStruct +{ + // + struct sDataStruct + { + // + double value; + double sumY; + double sumXY; + }; + + // + sDataStruct data[]; + + // + int dataSize; + int period; + double sumX; + double sumXX; + double divisor; + + // + // Constructor ... + XLinearRegressionWorkStruct() : dataSize(-1), period(-1) {} +}; + +// +struct XLinearRegression +{ + // + XLinearRegressionWorkStruct m_work; + + // + // Calculate Linear Regression ... + double Calculate( + double value, + int period, + double &_slope, + double &_intercept, + int r, + int bars // + ) + { + // + if (m_work.dataSize <= bars) + { + m_work.dataSize = ArrayResize(m_work.data, bars + 500, 2000); + } + + // + if (period < 1) + { + period = 1; + } + + // + if (m_work.period != (int)period) + { + // + m_work.period = (int)period; + m_work.sumX = m_work.period * (m_work.period - 1.0) / 2.0; + m_work.sumXX = m_work.period * (m_work.period - 1.0) * (2.0 * m_work.period - 1.0) / 6.0; + m_work.divisor = m_work.sumX * m_work.sumX - m_work.period * m_work.sumXX; + + // + if (m_work.divisor) + { + m_work.divisor = 1.0 / m_work.divisor; + } + } + + // + m_work.data[r].value = value; + + // + if (r >= m_work.period) + { + // + m_work.data[r].sumY = m_work.data[r - 1].sumY + value - m_work.data[r - m_work.period].value; + m_work.data[r].sumXY = m_work.data[r - 1].sumXY + m_work.data[r].sumY - m_work.data[r - m_work.period].value * (m_work.period - 1.0) - value; + } + else + { + // + m_work.data[r].sumY = value; + m_work.data[r].sumXY = 0; + + // + for (int k = 1; k < m_work.period && r >= k; k++) + { + // + m_work.data[r].sumY += m_work.data[r - k].value; + m_work.data[r].sumXY += k * m_work.data[r - k].value; + } + } + + // + _slope = (m_work.period * m_work.data[r].sumXY - m_work.sumX * m_work.data[r].sumY) * m_work.divisor; + _intercept = (m_work.data[r].sumY - _slope * m_work.sumX) / (double)m_work.period; + + // + double result = (_intercept + _slope * (m_work.period - 1.0)); + + // + return result; + } + + // +}; + // // Styling Buffers ... @@ -4504,6 +4618,38 @@ double GetAppliedPrice( return (0); } +// +double iGetPrice( + int tprice, + double open, + double high, + const double low, + const double close // +) +{ + // + switch (tprice) + { + case PRICE_CLOSE: + return (close); + case PRICE_OPEN: + return (open); + case PRICE_HIGH: + return (high); + case PRICE_LOW: + return (low); + case PRICE_MEDIAN: + return ((high + low) / 2.0); + case PRICE_TYPICAL: + return ((high + low + close) / 3.0); + case PRICE_WEIGHTED: + return ((high + low + close + close) / 4.0); + } + + // + return (0); +} + // // Calculate TP/SL for Specified Type of Positions ... void CalculateTPSL(