/////////////////////////////////////////////////////// // SaherElm IT Center MQL5 Indicator // ------------------------------------------- // Name: XHTD // Description: HULL Trend Detector ... // // 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 XHTD Indicator" #property strict // #define ShortName "XHTD" // // Imports ... #include "../Libraries/x-saherelm.common.lib.mq5" // // Inputs ... // input group "Market"; input int length = 14; // Length input ENUM_APPLIED_PRICE appliedTo = PRICE_CLOSE; // Applied To input double multiplier = 0.66; // Multiplier // input group "Presentation"; input bool show = true; // Show // // Buffers ... // #property indicator_chart_window // #property indicator_buffers 2 #property indicator_plots 2 // #define mainBufferIndex 0 double mainBuffer[]; // #define mainBufferColorIndex 1 double mainBufferColor[]; // #define hideColorIDX 0 #define bullColorIDX 1 #define bearColorIDX 2 // #property indicator_label1 "XHTD" #property indicator_type1 DRAW_COLOR_LINE #property indicator_color1 CLR_NONE, clrGreen, clrDarkRed #property indicator_style1 STYLE_DOT #property indicator_width1 1 // #define upBufferIndex 2 double upBuffer[]; // #define downBufferIndex 3 double downBuffer[]; // #define directionBufferIndex 4 double directionBuffer[]; // // Event Handlers ... // // Initialization ... int OnInit() { // // Validate Inputs ... if (!ValidateInputs()) { return INIT_PARAMETERS_INCORRECT; } // // 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 ... ) { // if (ArraySize(directionBuffer) != rates_total) { // ArrayResize(upBuffer, rates_total); ArrayResize(downBuffer, rates_total); ArrayResize(directionBuffer, rates_total); } // for (int i = (int)MathMax(prev_calculated - 1, 1); i < rates_total; i++) { // double atr = 0; for (int k = 0; k < length && (i - k - 1) >= 0; k++) { atr += MathMax(high[i - k], close[i - k - 1]) - MathMin(low[i - k], close[i - k - 1]); } // atr /= length; // double cprice = close[i]; double appliedPrice = getPrice( appliedTo, open, close, high, low, i, rates_total // ); double mprice = iHull( appliedPrice, length, i, rates_total // ); // upBuffer[i] = mprice + multiplier * atr; downBuffer[i] = mprice - multiplier * atr; // mainBufferColor[i] = mainBufferColor[i - 1]; directionBuffer[i] = directionBuffer[i - 1]; // if (cprice > upBuffer[i - 1]) { directionBuffer[i] = 1; } // if (cprice < downBuffer[i - 1]) { directionBuffer[i] = -1; } // if (directionBuffer[i] > 0) { // downBuffer[i] = MathMax(downBuffer[i], downBuffer[i - 1]); // mainBuffer[i] = downBuffer[i]; } else { // upBuffer[i] = MathMin(upBuffer[i], upBuffer[i - 1]); // mainBuffer[i] = upBuffer[i]; } // if (directionBuffer[i] == 1) { mainBufferColor[i] = bullColorIDX; } // if (directionBuffer[i] == -1) { mainBufferColor[i] = bearColorIDX; } } // return rates_total; } // // Custom Functions ... // // Validate Input Args for Initialization ... bool ValidateInputs() { // bool result = false; // result = length >= 2 && multiplier > 0; // 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() { // // Main ... ENUM_DRAW_TYPE mainDrawType = show ? DRAW_COLOR_LINE : DRAW_NONE; // PlotIndexSetInteger(mainBufferIndex, PLOT_SHOW_DATA, true); SetIndexBuffer(mainBufferIndex, mainBuffer, INDICATOR_DATA); PlotIndexSetInteger(mainBufferIndex, PLOT_DRAW_TYPE, mainDrawType); SetIndexBuffer(mainBufferColorIndex, mainBufferColor, INDICATOR_COLOR_INDEX); // SetIndexBuffer(upBufferIndex, upBuffer, INDICATOR_CALCULATIONS); // SetIndexBuffer(downBufferIndex, downBuffer, INDICATOR_CALCULATIONS); // SetIndexBuffer(directionBufferIndex, directionBuffer, INDICATOR_CALCULATIONS); } // // Hull Handler ... double workHull[][2]; double iHull( double price, double period, int r, int bars, int instanceNo = 0 // ) { // if (ArrayRange(workHull, 0) != bars) { ArrayResize(workHull, bars); } // int HmaPeriod = (int)MathMax(period, 2); int HalfPeriod = (int)MathFloor(HmaPeriod / 2); int HullPeriod = (int)MathFloor(MathSqrt(HmaPeriod)); double hma, hmw, weight; instanceNo *= 2; // workHull[r][instanceNo] = price; // hmw = HalfPeriod; hma = hmw * price; for (int k = 1; k < HalfPeriod && (r - k) >= 0; k++) { // weight = HalfPeriod - k; hmw += weight; hma += weight * workHull[r - k][instanceNo]; } workHull[r][instanceNo + 1] = 2.0 * hma / hmw; // hmw = HmaPeriod; hma = hmw * price; for (int k = 1; k < period && (r - k) >= 0; k++) { // weight = HmaPeriod - k; hmw += weight; hma += weight * workHull[r - k][instanceNo]; } workHull[r][instanceNo + 1] -= hma / hmw; // hmw = HullPeriod; hma = hmw * workHull[r][instanceNo + 1]; for (int k = 1; k < HullPeriod && (r - k) >= 0; k++) { // weight = HullPeriod - k; hmw += weight; hma += weight * workHull[r - k][1 + instanceNo]; } // return (hma / hmw); } // double getPrice(ENUM_APPLIED_PRICE price, const double& open[], const double& close[], const double& high[], const double& low[], int i, int bars) { switch (price) { case PRICE_CLOSE: return(close[i]); case PRICE_OPEN: return(open[i]); case PRICE_HIGH: return(high[i]); case PRICE_LOW: return(low[i]); case PRICE_MEDIAN: return((high[i]+low[i])/2.0); case PRICE_TYPICAL: return((high[i]+low[i]+close[i])/3.0); case PRICE_WEIGHTED: return((high[i]+low[i]+close[i]+close[i])/4.0); //case PRICE_AVERAGE: return((high[i]+low[i]+close[i]+open[i])/4.0); } return(0); } //