#property version "2.00" #property indicator_chart_window #property indicator_buffers 3 #property indicator_plots 3 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_type3 DRAW_LINE #property indicator_width1 1 #property indicator_width2 1 #property indicator_width3 1 #property indicator_color1 clrBlue #property indicator_color2 clrGreen #property indicator_color3 clrRed #property indicator_style1 STYLE_SOLID #property indicator_style2 STYLE_SOLID #property indicator_style3 STYLE_SOLID double avgLine[]; double upperTrendline[]; double LowerTrendline[]; double upperBand[2147483]; // keep track of upperband values double lowerBand[2147483]; // keep track of lowerband values bool trend = true; // Trend direction status bool trends[2147483]; // keep track of the trend status double trend_line[2147483]; // keep track of trendline values // Custom functions // Calculates the median of an array //@param array [in] (array[]) that will be used for the calculation //@returns (double) double ArrayMedian(const double& array[]) { double median; double copy[]; int lenght = ArraySize(array); ArrayResize(copy, lenght); ArrayCopy(copy, array, 0, 0, WHOLE_ARRAY); ArraySort(copy); if (lenght % 2 == 0) // it's even { median = (copy[lenght / 2] + copy[(lenght / 2) - 1]) / 2.0; } else // it's odd { median = copy[lenght / 2]; } return (median); } // Calculates the average of an array //@param array [in] (array[]) that will be used for the calculation //@returns (double) double ArrayAvg(const double& array[]) { double sum = 0; double avg; for (int i = 0; i < ArraySize(array); i++) { sum += array[i]; } avg = sum / ArraySize(array); return (avg); } //Calculates the mode of an array //@param array [in] (array[]) that will be used for the calculation //@returns (double) double ArrayMode(const double& array[]) { double maxValue = -1.0; int maxCount = 0; for (int i = 0; i < ArraySize(array); i++) { double currentValue = array[i]; int currentCount = 1; for (int j = i + 1; j < ArraySize(array); j++) { if (array[j] == currentValue) { currentCount++; } } if (currentCount > maxCount) { maxCount = currentCount; maxValue = currentValue; } else if (currentCount == maxCount) { if (currentValue < maxValue) { maxValue = currentValue; } } } return (maxValue); } // Inputs input string separator = "========CALCULATION INPUTS========="; input int bars = 1000; // Max History Bars input bool show_strength = false; // Show Trend Strength input int len = 20; // Lenght enum Type { type1 = 1, // AVG type2 = 2, // MEADIAN type3 = 3, // MODE }; input Type mode = type1; // Type input double distance = 1; // Distance input bool show_retest = false; // Retest Signals input string separator2 = "========STRONG SIGNAL SHAPES INPUTS========="; input ENUM_OBJECT objSell = OBJ_ARROW_DOWN; // sell signal shape (strong) input ENUM_OBJECT objBuy = OBJ_ARROW_UP; // buy signal shape (strong) input int sellSigSize = 3; // sell signal size (strong) input int buySigSize = 3; // buy signal size (strong) input color sellSigClr = clrNONE; // sell signal color (strong) input color buySigClr = clrNONE; // buy signal color (strong) input string separator3 = "========COMMON SIGNAL SHAPES INPUTS========="; input ENUM_OBJECT objSellcmn = OBJ_ARROW_DOWN; // sell signal shape input ENUM_OBJECT objBuycmn = OBJ_ARROW_UP; // buy signal shape input int sellSigSizecmn = 2; // sell signal size input int buySigSizecmn = 2; // buy signal size input color sellSigClrcmn = clrNONE; // sell signal color input color buySigClrcmn = clrNONE; // buy signal color input string separator4 = "========RETEST SIGNAL SHAPES INPUTS========="; input ENUM_OBJECT objSellrt = OBJ_ARROW_DOWN; // sell signal shape (retest) input ENUM_OBJECT objBuyrt = OBJ_ARROW_UP; // buy signal shape (retest) input int sellSigSizert = 1; // sell signal size (retest) input int buySigSizert = 1; // buy signal size (retest) input color sellSigClrrt = clrNONE; // sell signal color (retest) input color buySigClrrt = clrNONE; // buy signal color (retest) // Functions // Calculates a Gaussian filter for smoothing the data (uses close value as source) //@param length (int) Length of the filter //@param sigma (float) Standard deviation for the Gaussian function //@param shift (int) the index of the candle //@returns (float) Smoothed value for the current bar double Gaussian_filter(double lenght, double sigma, int shift) { double weights[100]; // Create an array to store weights for Gaussian filter double total = 0; // Sum of all weights, used for normalization double pi = M_PI; // Define Pi constant // Calculate weights for Gaussian filter for (int i = 0; i < lenght; i++) { double weight = MathExp(-0.5 * MathPow((i - lenght / 2) / sigma, 2.0)) / MathSqrt(sigma * 2.0 * pi); weights[i] = weight; total += weight; } // Normalize weights for (int i = 0; i < lenght; i++) { weights[i] = weights[i] / total; } // Apply Gaussian filter to the source series double sum = 0; for (int i = 0; i < lenght; i++) { sum = sum + iClose(_Symbol, PERIOD_CURRENT, shift) * weights[i]; shift++; } return (sum); } // Multi-trend calculation using Gaussian filter //@param values [out] (array[][]) //@param period [in] (int) Lookback period for trend calculation //@param shift [in] (int) the index of the candle //@returns Void void Multi_trend(double& values[], double period, int shift, int arrShift) { ArrayInitialize(values, 0); int shifti = shift; double g_value[]; // Array to store Gaussian filtered values // Calculate the average true range (ATR) volatility double range[100]; for (int i = 0; i < 100; i++) { range[i] = iHigh(_Symbol, PERIOD_CURRENT, shifti) - iLow(_Symbol, PERIOD_CURRENT, shifti); shifti++; } double volatility = ArrayAvg(range); double lower_band = 0; // Lower band for trend analysis double upper_band = 0; // Upper band for trend analysis double trend_line = 0; // Trend line value // Apply Gaussian filter with a step adjustment to calculate multiple trend lines for (int i = 0; i <= 20; i++) { double gaussian_filter = Gaussian_filter(period + i, 10, shift); ArrayResize(g_value, ArraySize(g_value) + 1); g_value[i] = gaussian_filter; } double coeff = 0.05; double score = 0.0; // Calculate score based on trend analysis for (int i = 0; i < ArraySize(g_value); i++) { double g_f = g_value[i]; if (g_f > g_value[0]) { score += coeff; } } // Determine value based on user-selected mode (AVG, MEDIAN, MODE) double value; switch (mode) { case 1: // AVG value = ArrayAvg(g_value); break; case 2: // Median value = ArrayMedian(g_value); break; case 3: // Mode value = ArrayMode(g_value); break; } lower_band = value - volatility * distance; // Calculate lower band based on value and volatility upper_band = value + volatility * distance; // Calculate upper band based on value and volatility lowerBand[arrShift] = lower_band; // save the band values upperBand[arrShift] = upper_band; // Check crossover and crossunder of price with bands to determine trend if (iClose(_Symbol, PERIOD_CURRENT, shift + 2) < upperBand[arrShift - 3] && iClose(_Symbol, PERIOD_CURRENT, shift+1) > upperBand[arrShift-2]) { trend = true; } else if (iClose(_Symbol, PERIOD_CURRENT, shift + 2) > lowerBand[arrShift - 3] && iClose(_Symbol, PERIOD_CURRENT, shift+1) < lowerBand[arrShift-2]) { trend = false; } // Set trend line based on trend direction if (trend) { trend_line = lower_band; } else if (!trend) { trend_line = upper_band; } values[0] = score; values[1] = value; values[2] = trend_line; } int OnInit() { //populate the arrays ArrayFill(lowerBand, 0, ArraySize(lowerBand), 0); ArrayFill(upperBand, 0, ArraySize(upperBand), 0); ArrayFill(trends, 0, ArraySize(trends), 0); ArrayFill(trend_line, 0, ArraySize(trend_line), 0); ArrayInitialize(lowerBand, 0); ArrayInitialize(upperBand, 0); ArrayInitialize(trends, 0); ArrayInitialize(trend_line, 0); ArrayInitialize(avgLine, 0); ArrayInitialize(upperTrendline, 0); ArrayInitialize(LowerTrendline, 0); //Set the buffers SetIndexBuffer(0, avgLine); SetIndexBuffer(1, upperTrendline); SetIndexBuffer(2, LowerTrendline); int height = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0); int width = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0); //Create labels to show the strength if (show_strength){ ObjectCreate(0, "StrengthUp", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, "StrengthUp", OBJPROP_CORNER, CORNER_LEFT_LOWER); ObjectSetInteger(0, "StrengthUp", OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(0, "StrengthUp", OBJPROP_FONTSIZE, 14); ObjectSetInteger(0, "StrengthUp", OBJPROP_XDISTANCE, width / 2); ObjectSetInteger(0, "StrengthUp", OBJPROP_YDISTANCE, height-100); ObjectCreate(0, "StrengthDown", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, "StrengthDown", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "StrengthDown", OBJPROP_ANCHOR, ANCHOR_CENTER); ObjectSetInteger(0, "StrengthDown", OBJPROP_FONTSIZE, 14); ObjectSetInteger(0, "StrengthDown", OBJPROP_XDISTANCE, width / 2); ObjectSetInteger(0, "StrengthDown", OBJPROP_YDISTANCE, height-30); } return (INIT_SUCCEEDED); } void OnDeinit(const int reason) { /* ObjectsDeleteAll(0, "Strength"); ObjectsDeleteAll(0, "retest"); ObjectsDeleteAll(0, "trend");*/ } 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[]) { ArraySetAsSeries(avgLine, false); ArraySetAsSeries(upperTrendline, false); ArraySetAsSeries(LowerTrendline, false); ArraySetAsSeries(time, false); ArraySetAsSeries(close, false); ArraySetAsSeries(high, false); ArraySetAsSeries(open, false); ArraySetAsSeries(low, false); ArrayInitialize(avgLine, 0); ArrayInitialize(upperTrendline, 0); ArrayInitialize(LowerTrendline, 0); int limit = prev_calculated-1; if (prev_calculated == 0) { limit = MathMax(rates_total-bars, 101); } else limit = MathMax(rates_total - prev_calculated,1000); for (int i = limit; i < rates_total; i++) { int shift = iBarShift(_Symbol, PERIOD_CURRENT, time[i]); if (shift==-1) return 0; double values[4]; Multi_trend(values, len, shift, i); double avg = values[1]; double score = values[0]; trend_line[i] = values[2]; avgLine[i] = avg; if (trend) { upperTrendline[i] = EMPTY_VALUE; LowerTrendline[i] = trend_line[i]; } else if (!trend) { LowerTrendline[i] = EMPTY_VALUE; upperTrendline[i] = trend_line[i]; } trends[i-1] = trend; //if (trends[i - 2] != trends[i-1]) // Check change in trend //{ string obName = "trend "+time[i]; if (close[i-1]>upperTrendline[i-2] && close[i-2] 0.5) { // Strong ObjectCreate(0, obName, objBuy, 0, time[i-1], low[i-1]); ObjectSetInteger(0, obName, OBJPROP_ANCHOR, ANCHOR_TOP); ObjectSetInteger(0, obName, OBJPROP_WIDTH, buySigSize); ObjectSetInteger(0, obName, OBJPROP_COLOR, buySigClr); } else if (score < 0.5) { // Common ObjectCreate(0, obName, objBuycmn, 0, time[i-1], low[i-1]); ObjectSetInteger(0, obName, OBJPROP_ANCHOR, ANCHOR_TOP); ObjectSetInteger(0, obName, OBJPROP_WIDTH, buySigSizecmn); ObjectSetInteger(0, obName, OBJPROP_COLOR, buySigClrcmn); } } if (close[i-1]LowerTrendline[i-3] && LowerTrendline[i-1]!=EMPTY_VALUE && LowerTrendline[i-2]!=EMPTY_VALUE) { // Sell signal obName = "guasss"+ time[i-1]; if (score < 0.5) { // Strong ObjectCreate(0, obName, objSell, 0, time[i-1], high[i-1]); ObjectSetInteger(0, obName, OBJPROP_ANCHOR, ANCHOR_BOTTOM); ObjectSetInteger(0, obName, OBJPROP_WIDTH, sellSigSize); ObjectSetInteger(0, obName, OBJPROP_COLOR, sellSigClr); } else if (score > 0.5) { // Common ObjectCreate(0, obName, objSellcmn, 0, time[i-1], high[i-1]); ObjectSetInteger(0, obName, OBJPROP_ANCHOR, ANCHOR_BOTTOM); ObjectSetInteger(0, obName, OBJPROP_WIDTH, sellSigSizecmn); ObjectSetInteger(0, obName, OBJPROP_COLOR, sellSigClrcmn); } } // } if (show_retest) { if (high[i - 1] > avgLine[i - 1] && high[i] < avgLine[i] && !trend) { // Sell retest obName = "guasss"+ time[i-1]; ObjectCreate(0, obName, objSellrt, 0, time[i-1], high[i-1]); ObjectSetInteger(0, obName, OBJPROP_ANCHOR, ANCHOR_BOTTOM); ObjectSetInteger(0, obName, OBJPROP_WIDTH, sellSigSizert); ObjectSetInteger(0, obName, OBJPROP_COLOR, sellSigClrrt); } if (close[i - 2] < avgLine[i - 2] && close[i-1] > avgLine[i-1] && trend) { // Buy retest string obName = "retest "+time[i-1]; ObjectCreate(0, obName, objBuyrt, 0, time[i-1], low[i-1]); ObjectSetInteger(0, obName, OBJPROP_ANCHOR, ANCHOR_TOP); ObjectSetInteger(0, obName, OBJPROP_WIDTH, buySigSizert); ObjectSetInteger(0, obName, OBJPROP_COLOR, buySigClrrt); } } // Display strength double score_up = MathRound(((score - 1) * -1)*100); double score_dn = 100 - score_up; if (score_up < 0) { score_up = 0; score_dn = 100; } if (show_strength){ ObjectSetString(0, "StrengthUp", OBJPROP_TEXT, "UP Strength " + score_up + "%"); ObjectSetString(0, "StrengthDown", OBJPROP_TEXT, "DOWN strength " + score_dn + "%"); } } return (rates_total); }