// Stoch_Mod.mq4 // Idea & money: Razial187, https://www.mql5.com/en/users/razial187 // Code: Alexander Puzanov, moonscript@gmail.com, https://www.mql5.com/en/users/f2011 #define Version_Date "22.03.2022 10:00" #define Version_Num "1.03" #define Arrows_Displacement 0.0001 #property copyright "Razial187" #property version Version_Num #property strict #property indicator_separate_window #property indicator_buffers 14 #property indicator_label1 "%K - %D" #property indicator_color1 clrDodgerBlue #property indicator_type1 DRAW_HISTOGRAM #property indicator_width1 3 #property indicator_label2 "%K - %D" #property indicator_color2 clrDeepPink #property indicator_type2 DRAW_HISTOGRAM #property indicator_width2 3 #property indicator_label3 "Stoch Raw %K" #property indicator_color3 clrGray #property indicator_type3 DRAW_LINE #property indicator_style3 STYLE_SOLID #property indicator_width3 2 #property indicator_label4 "Stoch %K" #property indicator_color4 clrBlue #property indicator_type4 DRAW_LINE #property indicator_style4 STYLE_SOLID #property indicator_width4 2 #property indicator_label5 "Stoch %D" #property indicator_color5 clrRed #property indicator_type5 DRAW_LINE #property indicator_style5 STYLE_SOLID #property indicator_width5 3 #property indicator_label6 "Bullish Diver" #property indicator_color6 clrLime #property indicator_type6 DRAW_ARROW #property indicator_width6 1 #property indicator_label7 "Bearish Diver" #property indicator_color7 clrRed #property indicator_type7 DRAW_ARROW #property indicator_width7 1 #property indicator_label8 "Arrow" #property indicator_color8 clrSlateBlue #property indicator_type8 DRAW_ARROW #property indicator_width8 5 #property indicator_label9 "Output" #property indicator_type9 DRAW_NONE #property indicator_width9 0 #property indicator_label10 "OverBought" #property indicator_color10 clrSilver #property indicator_type10 DRAW_LINE #property indicator_style10 STYLE_DOT #property indicator_width10 1 #property indicator_label11 "OverSold" #property indicator_color11 clrSilver #property indicator_type11 DRAW_LINE #property indicator_style11 STYLE_DOT #property indicator_width11 1 #property indicator_label12 "Extreme OverBought" #property indicator_color12 clrSilver #property indicator_type12 DRAW_LINE #property indicator_style12 STYLE_DOT #property indicator_width12 1 #property indicator_label13 "Extreme OverSold" #property indicator_color13 clrSilver #property indicator_type13 DRAW_LINE #property indicator_style13 STYLE_DOT #property indicator_width13 1 #property indicator_label14 "Zero Level" #property indicator_color14 clrSilver #property indicator_type14 DRAW_LINE #property indicator_style14 STYLE_DASH #property indicator_width14 1 input int Stoch_Period_K = 9; // Stochastic: %K Period input bool Stoch_Show_Raw_K = false; // Stochastic: Show Raw K input bool Stoch_Show_Histo = false; // Stochastic: Show K-D Histogram input bool Stoch_Show_Histo_Zero_Level = true; // Stochastic: Show K-D Histogram Zero Level input uint Bars_Limit = 1000; // Stochastic: Lookback Bars input string  01 = ""; //   input double Zone_OverBought = 70; // Zone: OverBought input double Zone_OverBought_Extreme = 85; // Zone: Extreme OverBought input double Zone_OverSold = 30; // Zone: OverSold input double Zone_OverSold_Extreme = 15; // Zone: Extreme OverSold input uint Level_Extension_Bars = 100; // Levels Extension Bars input string  02 = ""; //   input bool Diver_Regular = true; // Divergence: Regular input bool Diver_Hidden = true; // Divergence: Hidden input bool drawIndicatorTrendLines = true; // Divergence: Draw Indicator Trend Lines input bool drawPriceTrendLines = false; // Divergence: Draw Price Trend Lines bool Show_Output = false; // Divergence: Show Output input string  03 = ""; //   input bool Alert_Zone_Standard = false; // Zone Alert: Standard Zone input bool Alert_Zone_Extreme = false; // Zone Alert: Extreme Zone input bool Alert_Diver_Regular = false; // Divergence Alert: Regular input bool Alert_Diver_Hidden = false; // Divergence Alert: Hidden input bool Alert_Cross = false; // K/D Cross Alert: On input bool Alert_Popup = false; // Alert Option: Show popup input bool Alert_Push = false; // Alert Option: Send push-notification input bool Alert_Email = false; // Alert Option: Send eMail datetime gt_Last_Bar = 0, gt_Cross_Alert = 0, gt_Zone_OverBought_Alert = 0, gt_Zone_OverBought_Extreme_Alert = 0, gt_Zone_OverSold_Alert = 0, gt_Zone_OverSold_Extreme_Alert = 0, gt_Diver_Regular_Alert = 0, gt_Diver_Hidden_Alert = 0 ; static datetime lastAlertTime; static string gs_Prefix; bool gb_Alerts_On ; double buff_Zone_OverBought[], buff_Zone_OverBought_Extreme[], buff_Zone_OverSold[], buff_Zone_OverSold_Extreme[], buff_K_Raw_Line[], buff_K_Line[], buff_D_Line[], buff_K_Raw[], buff_Bullish_Diver[], buff_Bearish_Diver[], buff_Histo_Up[], buff_Histo_Down[], buff_Histo_Zero[], buff_Highes[], buff_Lowes[], buff_Filtered[], buff_Output[] ; int OnInit(void) { gt_Last_Bar = 0; gb_Alerts_On = Alert_Email || Alert_Popup || Alert_Push; IndicatorBuffers(14 + 3); int i_Buffer_Num = WRONG_VALUE; SetIndexBuffer(++i_Buffer_Num, buff_Histo_Up); SetIndexEmptyValue(i_Buffer_Num, 0); SetIndexDrawBegin(i_Buffer_Num, Stoch_Period_K); SetIndexBuffer(++i_Buffer_Num, buff_Histo_Down); SetIndexEmptyValue(i_Buffer_Num, 0); SetIndexDrawBegin(i_Buffer_Num, Stoch_Period_K); SetIndexBuffer(++i_Buffer_Num, buff_K_Raw_Line); SetIndexEmptyValue(i_Buffer_Num, EMPTY_VALUE); SetIndexDrawBegin(i_Buffer_Num, Stoch_Period_K); SetIndexBuffer(++i_Buffer_Num, buff_K_Line); SetIndexEmptyValue(i_Buffer_Num, EMPTY_VALUE); SetIndexDrawBegin(i_Buffer_Num, Stoch_Period_K); SetIndexBuffer(++i_Buffer_Num, buff_D_Line); SetIndexEmptyValue(i_Buffer_Num, EMPTY_VALUE); SetIndexDrawBegin(i_Buffer_Num, Stoch_Period_K); SetIndexBuffer(++i_Buffer_Num, buff_Bullish_Diver); SetIndexEmptyValue(i_Buffer_Num, 0); SetIndexArrow(i_Buffer_Num, 233); SetIndexBuffer(++i_Buffer_Num, buff_Bearish_Diver); SetIndexEmptyValue(i_Buffer_Num, 0); SetIndexArrow(i_Buffer_Num, 234); SetIndexBuffer(++i_Buffer_Num, buff_Filtered); SetIndexEmptyValue(i_Buffer_Num, 0); SetIndexArrow(i_Buffer_Num, 161); SetIndexBuffer(++i_Buffer_Num, buff_Output); SetIndexEmptyValue(i_Buffer_Num, 0); SetIndexBuffer(++i_Buffer_Num, buff_Zone_OverBought); SetIndexShift(i_Buffer_Num, Level_Extension_Bars); SetIndexBuffer(++i_Buffer_Num, buff_Zone_OverSold); SetIndexShift(i_Buffer_Num, Level_Extension_Bars); SetIndexBuffer(++i_Buffer_Num, buff_Zone_OverBought_Extreme); SetIndexShift(i_Buffer_Num, Level_Extension_Bars); SetIndexBuffer(++i_Buffer_Num, buff_Zone_OverSold_Extreme); SetIndexShift(i_Buffer_Num, Level_Extension_Bars); SetIndexBuffer(++i_Buffer_Num, buff_Histo_Zero); SetIndexEmptyValue(i_Buffer_Num, EMPTY_VALUE); SetIndexShift(i_Buffer_Num, Level_Extension_Bars); SetIndexBuffer(++i_Buffer_Num, buff_Highes); SetIndexBuffer(++i_Buffer_Num, buff_Lowes); SetIndexBuffer(++i_Buffer_Num, buff_K_Raw); ArraySetAsSeries(buff_Histo_Up, false); ArraySetAsSeries(buff_Histo_Down, false); ArraySetAsSeries(buff_K_Raw_Line, false); ArraySetAsSeries(buff_K_Raw, false); ArraySetAsSeries(buff_K_Line, false); ArraySetAsSeries(buff_D_Line, false); ArraySetAsSeries(buff_Highes, false); ArraySetAsSeries(buff_Lowes, false); ArraySetAsSeries(buff_Histo_Zero, false); gs_Prefix = StringFormat("Sto(%i)Mod", Stoch_Period_K); IndicatorShortName(gs_Prefix); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { gt_Last_Bar = 0; ObjectsDeleteAll(0, gs_Prefix); } 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(gt_Last_Bar < 1) { ObjectsDeleteAll(0, gs_Prefix); ArrayInitialize(buff_Histo_Up, 0); ArrayInitialize(buff_Histo_Down, 0); ArrayInitialize(buff_Histo_Zero, (Stoch_Show_Histo && Stoch_Show_Histo_Zero_Level) ? 0 : EMPTY_VALUE); ArrayInitialize(buff_K_Line, EMPTY_VALUE); ArrayInitialize(buff_K_Raw_Line, EMPTY_VALUE); ArrayInitialize(buff_K_Raw, EMPTY_VALUE); ArrayInitialize(buff_D_Line, EMPTY_VALUE); ArrayInitialize(buff_Bearish_Diver, 0); ArrayInitialize(buff_Bullish_Diver, 0); ArrayInitialize(buff_Output, 0); ArrayInitialize(buff_Filtered, 0); ArrayInitialize(buff_Zone_OverBought, Zone_OverBought); ArrayInitialize(buff_Zone_OverSold, Zone_OverSold); ArrayInitialize(buff_Zone_OverBought_Extreme, Zone_OverBought_Extreme); ArrayInitialize(buff_Zone_OverSold_Extreme, Zone_OverSold_Extreme); if(rates_total < int(Bars_Limit)) { iBars(_Symbol, PERIOD_CURRENT); return(rates_total); } gt_Last_Bar = 1; } bool b_Is_New_Bar = gt_Last_Bar != Time[0]; gt_Last_Bar = Time[0]; if(!b_Is_New_Bar) return(rates_total); ArrayInitialize(buff_Zone_OverBought, Zone_OverBought); ArrayInitialize(buff_Zone_OverSold, Zone_OverSold); ArrayInitialize(buff_Zone_OverBought_Extreme, Zone_OverBought_Extreme); ArrayInitialize(buff_Zone_OverSold_Extreme, Zone_OverSold_Extreme); int i_Bar, i_Period_Bar, i_First_Bar ; double d_Min, d_Max, d_Range ; if(rates_total <= Stoch_Period_K) return(0); ArraySetAsSeries(buff_K_Line, false); ArraySetAsSeries(low, false); ArraySetAsSeries(high, false); ArraySetAsSeries(close, false); ArraySetAsSeries(open, false); ArraySetAsSeries(time, false); i_First_Bar = Stoch_Period_K - 1; if(i_First_Bar + 1 < prev_calculated) i_First_Bar = prev_calculated - 2; else for(i_Bar = 0; i_Bar < i_First_Bar; i_Bar++) buff_Lowes[i_Bar] = buff_Highes[i_Bar] = 0.0; for(i_Bar = i_First_Bar; i_Bar < rates_total && !IsStopped(); i_Bar++) { d_Min = 1000000.0; d_Max = -1000000.0; for(i_Period_Bar = i_Bar - Stoch_Period_K + 1; i_Period_Bar <= i_Bar; i_Period_Bar++) { if(d_Min > low[i_Period_Bar]) d_Min = low[i_Period_Bar]; if(d_Max < high[i_Period_Bar]) d_Max = high[i_Period_Bar]; } buff_Lowes[i_Bar] = d_Min; buff_Highes[i_Bar] = d_Max; } i_First_Bar = Stoch_Period_K - 1; if(i_First_Bar + 1 < prev_calculated) i_First_Bar = prev_calculated - 2; else for(i_Bar = 0; i_Bar < i_First_Bar; i_Bar++) buff_K_Raw[i_Bar] = 0.0; for(i_Bar = i_First_Bar; i_Bar < rates_total && !IsStopped(); i_Bar++) { d_Range = buff_Highes[i_Bar] == buff_Lowes[i_Bar] ? _Point : buff_Highes[i_Bar] - buff_Lowes[i_Bar]; buff_K_Raw[i_Bar] = 100.0 * (close[i_Bar] - buff_Lowes[i_Bar]) / d_Range; buff_K_Line[i_Bar] = buff_K_Line[i_Bar - 1] * 0.6667 + buff_K_Raw[i_Bar] * 0.3333; buff_D_Line[i_Bar] = buff_D_Line[i_Bar - 1] * 0.6667 + buff_K_Line[i_Bar] * 0.3333; buff_K_Raw_Line[i_Bar] = Stoch_Show_Raw_K ? buff_K_Raw[i_Bar] : EMPTY_VALUE; if(Stoch_Show_Histo) { buff_Histo_Up[i_Bar] = buff_K_Line[i_Bar] - buff_D_Line[i_Bar]; if(buff_Histo_Up[i_Bar] < 0) { buff_Histo_Down[i_Bar] = buff_Histo_Up[i_Bar]; buff_Histo_Up[i_Bar] = 0; } } } i_Bar = rates_total - 1; if(gb_Alerts_On && Alert_Cross) { if(gt_Cross_Alert < Time[i_Bar] && buff_K_Line[i_Bar] >= buff_D_Line[i_Bar] && buff_K_Line[i_Bar - 1] < buff_D_Line[i_Bar - 1]) { f_Do_Alert("K/D Cross Up", "Stoch Mod Cross", Alert_Popup, false, Alert_Email, Alert_Push); gt_Cross_Alert = TimeCurrent(); } if(gt_Cross_Alert < Time[i_Bar] && buff_K_Line[i_Bar] <= buff_D_Line[i_Bar] && buff_K_Line[i_Bar - 1] > buff_D_Line[i_Bar - 1]) { f_Do_Alert("K/D Cross Down", "Stoch Mod Cross", Alert_Popup, false, Alert_Email, Alert_Push); gt_Cross_Alert = TimeCurrent(); } } if(gb_Alerts_On && Alert_Zone_Standard) { if(gt_Zone_OverBought_Alert < Time[i_Bar] && buff_K_Line[i_Bar] >= Zone_OverBought && buff_K_Line[i_Bar - 1] < Zone_OverBought) { f_Do_Alert("OverBought Zone", "Stoch Mod Zone", Alert_Popup, false, Alert_Email, Alert_Push); gt_Zone_OverBought_Alert = TimeCurrent(); } if(gt_Zone_OverSold_Alert < Time[i_Bar] && buff_K_Line[i_Bar] <= Zone_OverSold && buff_K_Line[i_Bar - 1] > Zone_OverSold) { f_Do_Alert("OverSold Zone", "Stoch Mod Zone", Alert_Popup, false, Alert_Email, Alert_Push); gt_Zone_OverSold_Alert = TimeCurrent(); } } if(gb_Alerts_On && Alert_Zone_Extreme) { if(gt_Zone_OverBought_Extreme_Alert < Time[i_Bar] && buff_K_Line[i_Bar] >= Zone_OverBought_Extreme && buff_K_Line[i_Bar - 1] < Zone_OverBought_Extreme) { f_Do_Alert("Extreme OverBought Zone", "Stoch Mod Zone", Alert_Popup, false, Alert_Email, Alert_Push); gt_Zone_OverBought_Extreme_Alert = TimeCurrent(); } if(gt_Zone_OverSold_Extreme_Alert < Time[i_Bar] && buff_K_Line[i_Bar] <= Zone_OverSold_Extreme && buff_K_Line[i_Bar - 1] > Zone_OverSold_Extreme) { f_Do_Alert("Extreme OverSold Zone", "Stoch Mod Zone", Alert_Popup, false, Alert_Email, Alert_Push); gt_Zone_OverSold_Extreme_Alert = TimeCurrent(); } } ArraySetAsSeries(buff_K_Line, true); f_Calculate_Indicator(prev_calculated - 1); f_Calculate_Output(Bars_Limit); return(rates_total); } void f_Calculate_Indicator(int countedBars) { int i_Bar = Bars - countedBars; // if(Bars_Limit > 0) i_Bar = int(fmin(i_Bar, Bars_Limit)); while(i_Bar-- > 0) { f_Catch_Bullish_Divergence(i_Bar + 2); f_Catch_Bearish_Divergence(i_Bar + 2); if(Show_Output) f_Calculate_Output(Bars_Limit, i_Bar); } } void f_Catch_Bullish_Divergence(int i_Bar_Shift = 1) { if(i_Bar_Shift < 0 || i_Bar_Shift > Bars - 9) return; if(!fb_Is_Indicator_Trough(buff_K_Line, i_Bar_Shift)) return; int i_Last_Trough = fi_Get_Indicator_Last_Trough(buff_K_Line, i_Bar_Shift); if(i_Last_Trough > Bars - 1 || i_Last_Trough < 0) return; if(Diver_Regular) if(buff_K_Line[i_Bar_Shift] > buff_K_Line[i_Last_Trough] && Low[i_Bar_Shift] < Low[i_Last_Trough]) { buff_Bullish_Diver[i_Bar_Shift] = buff_K_Line[i_Bar_Shift] - Arrows_Displacement; if(drawPriceTrendLines) DrawPriceTrendLine(Time[i_Bar_Shift], Time[i_Last_Trough], Low[i_Bar_Shift], Low[i_Last_Trough], clrLime, STYLE_SOLID); if(drawIndicatorTrendLines) DrawIndicatorTrendLine(Time[i_Bar_Shift], Time[i_Last_Trough], buff_K_Line[i_Bar_Shift], buff_K_Line[i_Last_Trough], clrLime, STYLE_SOLID); if(gb_Alerts_On && Alert_Diver_Regular && i_Bar_Shift <= 2) if(Time[i_Bar_Shift] != gt_Diver_Regular_Alert) { gt_Diver_Regular_Alert = Time[i_Bar_Shift]; f_Do_Alert("Classical bullish divergence", "Stoch Mod Diver", Alert_Popup, false, Alert_Email, Alert_Push); } } if(Diver_Hidden) if(buff_K_Line[i_Bar_Shift] < buff_K_Line[i_Last_Trough] && Low[i_Bar_Shift] > Low[i_Last_Trough]) { buff_Bullish_Diver[i_Bar_Shift] = buff_K_Line[i_Bar_Shift] - Arrows_Displacement; if(drawPriceTrendLines) DrawPriceTrendLine(Time[i_Bar_Shift], Time[i_Last_Trough], Low[i_Bar_Shift], Low[i_Last_Trough], clrLime, STYLE_DOT); if(drawIndicatorTrendLines) DrawIndicatorTrendLine(Time[i_Bar_Shift], Time[i_Last_Trough], buff_K_Line[i_Bar_Shift], buff_K_Line[i_Last_Trough], clrLime, STYLE_DOT); if(gb_Alerts_On && Alert_Diver_Hidden && i_Bar_Shift <= 2) if(Time[i_Bar_Shift] != gt_Diver_Hidden_Alert) { gt_Diver_Hidden_Alert = Time[i_Bar_Shift]; f_Do_Alert("Reverse bullish divergence", "Stoch Mod Diver", Alert_Popup, false, Alert_Email, Alert_Push); } } } void f_Catch_Bearish_Divergence(int i_Bar_Shift = 1) { if(i_Bar_Shift < 0 || i_Bar_Shift > Bars - 9) return; if(!fb_Is_Indicator_Peak(buff_K_Line, i_Bar_Shift)) return; int i_Last_Peak = fi_Get_Indicator_Last_Peak(buff_K_Line, i_Bar_Shift); if(i_Last_Peak > Bars - 1 || i_Last_Peak < 0) return; if(Diver_Regular) if(buff_K_Line[i_Bar_Shift] < buff_K_Line[i_Last_Peak] && High[i_Bar_Shift] > High[i_Last_Peak]) { buff_Bearish_Diver[i_Bar_Shift] = buff_K_Line[i_Bar_Shift] + Arrows_Displacement; if(drawPriceTrendLines) DrawPriceTrendLine(Time[i_Bar_Shift], Time[i_Last_Peak], High[i_Bar_Shift], High[i_Last_Peak], clrRed, STYLE_SOLID); if(drawIndicatorTrendLines) DrawIndicatorTrendLine(Time[i_Bar_Shift], Time[i_Last_Peak], buff_K_Line[i_Bar_Shift], buff_K_Line[i_Last_Peak], clrRed, STYLE_SOLID); if(gb_Alerts_On && Alert_Diver_Regular && i_Bar_Shift <= 2) if(Time[i_Bar_Shift] != gt_Diver_Regular_Alert) { gt_Diver_Regular_Alert = Time[i_Bar_Shift]; f_Do_Alert("Classical bearish divergence", "Stoch Mod Diver", Alert_Popup, false, Alert_Email, Alert_Push); } } if(Diver_Hidden) if(buff_K_Line[i_Bar_Shift] > buff_K_Line[i_Last_Peak] && High[i_Bar_Shift] < High[i_Last_Peak]) { buff_Bearish_Diver[i_Bar_Shift] = buff_K_Line[i_Bar_Shift] + Arrows_Displacement; if(drawPriceTrendLines) DrawPriceTrendLine(Time[i_Bar_Shift], Time[i_Last_Peak], High[i_Bar_Shift], High[i_Last_Peak], clrRed, STYLE_DOT); if(drawIndicatorTrendLines) DrawIndicatorTrendLine(Time[i_Bar_Shift], Time[i_Last_Peak], buff_K_Line[i_Bar_Shift], buff_K_Line[i_Last_Peak], clrRed, STYLE_DOT); if(gb_Alerts_On && Alert_Diver_Hidden && i_Bar_Shift <= 2) if(Time[i_Bar_Shift] != gt_Diver_Hidden_Alert) { gt_Diver_Hidden_Alert = Time[i_Bar_Shift]; f_Do_Alert("Reverse bearish divergence", "Stoch Mod Diver", Alert_Popup, false, Alert_Email, Alert_Push); } } } bool fb_Is_Indicator_Peak(const double& buff_Indicator_Values[], int i_Bar_Shift = 1) { if(i_Bar_Shift > Bars - 3 || i_Bar_Shift < 1) return(false); return( buff_Indicator_Values[i_Bar_Shift] >= buff_Indicator_Values[i_Bar_Shift + 1] && buff_Indicator_Values[i_Bar_Shift] > buff_Indicator_Values[i_Bar_Shift + 2] && buff_Indicator_Values[i_Bar_Shift] > buff_Indicator_Values[i_Bar_Shift - 1] ); } bool fb_Is_Indicator_Trough(const double& buff_Indicator_Values[], int i_Bar_Shift = 1) { if(i_Bar_Shift > Bars - 3 || i_Bar_Shift < 1) return(false); return( buff_Indicator_Values[i_Bar_Shift] <= buff_Indicator_Values[i_Bar_Shift + 1] && buff_Indicator_Values[i_Bar_Shift] < buff_Indicator_Values[i_Bar_Shift + 2] && buff_Indicator_Values[i_Bar_Shift] < buff_Indicator_Values[i_Bar_Shift - 1] ); } int fi_Get_Indicator_Last_Peak(const double& buff_Indicator_Values[], int i_Bar_Shift) { for(int i_Bar = i_Bar_Shift + 5; i_Bar < Bars - 3; i_Bar++) { if( buff_Indicator_Values[i_Bar] >= buff_Indicator_Values[i_Bar + 1] && buff_Indicator_Values[i_Bar] >= buff_Indicator_Values[i_Bar + 2] && buff_Indicator_Values[i_Bar] >= buff_Indicator_Values[i_Bar - 1] && buff_Indicator_Values[i_Bar] >= buff_Indicator_Values[i_Bar - 2] ) return(i_Bar); } return(WRONG_VALUE); } int fi_Get_Indicator_Last_Trough(const double& buff_Indicator_Values[], int i_Bar_Shift) { for(int i_Bar = i_Bar_Shift + 5; i_Bar < Bars - 3; i_Bar++) { if( buff_Indicator_Values[i_Bar] <= buff_Indicator_Values[i_Bar + 1] && buff_Indicator_Values[i_Bar] <= buff_Indicator_Values[i_Bar + 2] && buff_Indicator_Values[i_Bar] <= buff_Indicator_Values[i_Bar - 1] && buff_Indicator_Values[i_Bar] <= buff_Indicator_Values[i_Bar - 2] ) return(i_Bar); } return(WRONG_VALUE); } void DrawPriceTrendLine(datetime x1, datetime x2, double y1, double y2, color lineColor, double style) { string label = gs_Prefix + "Line.0# " + DoubleToStr(x1, 0); ObjectDelete(label); ObjectCreate(label, OBJ_TREND, 0, x1, y1, x2, y2, 0, 0); ObjectSet(label, OBJPROP_RAY, 0); ObjectSet(label, OBJPROP_COLOR, lineColor); ObjectSet(label, OBJPROP_STYLE, style); } void DrawIndicatorTrendLine(datetime x1, datetime x2, double y1, double y2, color lineColor, double style) { int indicatorWindow = WindowFind(gs_Prefix); if(indicatorWindow < 0) return; string label = gs_Prefix + "Line.0$# " + DoubleToStr(x1, 0); ObjectDelete(label); ObjectCreate(label, OBJ_TREND, indicatorWindow, x1, y1, x2, y2, 0, 0); ObjectSet(label, OBJPROP_RAY, 0); ObjectSet(label, OBJPROP_COLOR, lineColor); ObjectSet(label, OBJPROP_STYLE, style); } void f_Calculate_Output(int i_Lookback_Bars, int i_Bar_Shift = 0, int i_Bars_Limit = 0) { if(i_Bars_Limit <= 0) i_Bars_Limit = Bars - 2; if(i_Bar_Shift > i_Bars_Limit) return; double d_Band_Price = 0; int i_Last_Bearish_Diver = INT_MAX, i_Last_Bullish_Diver = INT_MAX, i_Bar = int(fmin(i_Bars_Limit, i_Bar_Shift + i_Lookback_Bars)) ; while(i_Bar-- > i_Bar_Shift) { if(buff_Bearish_Diver[i_Bar] != 0) { i_Last_Bearish_Diver = i_Bar; } if(buff_Bullish_Diver[i_Bar] != 0) { i_Last_Bullish_Diver = i_Bar; } } if(i_Last_Bearish_Diver < INT_MAX && i_Last_Bearish_Diver < i_Last_Bullish_Diver) buff_Output[i_Bar_Shift] = -i_Last_Bearish_Diver; else if(i_Last_Bullish_Diver < INT_MAX && i_Last_Bullish_Diver < i_Last_Bearish_Diver) buff_Output[i_Bar_Shift] = i_Last_Bullish_Diver; else buff_Output[i_Bar_Shift] = 0; if( Show_Output && (buff_Output[i_Bar_Shift] != buff_Output[i_Bar_Shift + 1]) && (buff_Output[i_Bar_Shift] != 0 && buff_Output[i_Bar_Shift + 1] != 0) ) buff_Filtered[i_Bar_Shift + 2] = buff_K_Line[i_Bar_Shift + 2]; } void f_Do_Alert(string s_Do_What, string s_Prefix = "", bool b_Alert = true, bool b_Sound = false, bool b_Email = false, bool b_Notification = false, string s_Sound = "alert.wav") { string s_Message; s_Message = StringFormat("%s | %s %s | %s", TimeToString(TimeLocal(), TIME_SECONDS), _Symbol, fs_TF_To_String(), s_Do_What); if(b_Alert) Alert(s_Message); if(b_Email) SendMail(StringConcatenate(s_Prefix, " ", _Symbol, " "), s_Message); if(b_Notification) SendNotification(s_Message); if(b_Sound) PlaySound(s_Sound); } string fs_TF_To_String(int i_Period = WRONG_VALUE) { if(i_Period < 0) i_Period = _Period; string s_TF_String; if(i_Period < 129600) { s_TF_String = StringSubstr(EnumToString(ENUM_TIMEFRAMES(i_Period)), 7); if(StringSubstr(s_TF_String, 0, 8) == "MEFRAMES") s_TF_String = StringSubstr(s_TF_String, 10); } else s_TF_String = i_Period == 129600 ? "Q1" : (i_Period == 259200 ? "Q2" : "Y"); return(s_TF_String); }