//------------------------------------------------------------------ #property copyright "© mladen, 2016, MetaQuotes Software Corp." #property link "www.forex-tsd.com, www.mql5.com" #property version "1.00" //------------------------------------------------------------------ #property indicator_separate_window #property indicator_buffers 9 #property indicator_plots 5 #property indicator_label1 "Setiment zone oscillator levels" #property indicator_type1 DRAW_FILLING #property indicator_color1 clrLimeGreen,clrOrange #property indicator_label2 "Setiment zone oscillator up level" #property indicator_type2 DRAW_LINE #property indicator_color2 clrLimeGreen #property indicator_style2 STYLE_DOT #property indicator_label3 "Setiment zone oscillator middle level" #property indicator_type3 DRAW_LINE #property indicator_color3 clrSilver #property indicator_style3 STYLE_DOT #property indicator_label4 "Setiment zone oscillator down level" #property indicator_type4 DRAW_LINE #property indicator_color4 clrOrange #property indicator_style4 STYLE_DOT #property indicator_label5 "Setiment zone oscillator" #property indicator_type5 DRAW_COLOR_LINE #property indicator_color5 clrSilver,clrLimeGreen,clrOrange #property indicator_width5 2 // // // // // enum enPrices { pr_close, // Close pr_open, // Open pr_high, // High pr_low, // Low pr_median, // Median pr_typical, // Typical pr_weighted, // Weighted pr_average, // Average (high+low+open+close)/4 pr_medianb, // Average median body (open+close)/2 pr_tbiased, // Trend biased price pr_tbiased2, // Trend biased (extreme) price pr_haclose, // Heiken ashi close pr_haopen , // Heiken ashi open pr_hahigh, // Heiken ashi high pr_halow, // Heiken ashi low pr_hamedian, // Heiken ashi median pr_hatypical, // Heiken ashi typical pr_haweighted, // Heiken ashi weighted pr_haaverage, // Heiken ashi average pr_hamedianb, // Heiken ashi median body pr_hatbiased, // Heiken ashi trend biased price pr_hatbiased2 // Heiken ashi trend biased (extreme) price }; enum enMaTypes { ma_sma, // Simple moving average ma_ema, // Exponential moving average ma_smma, // Smoothed MA ma_lwma, // Linear weighted MA ma_tema // Tripple exponential moving average }; enum enLevelType { lvl_floa, // Floating levels lvl_quan // Quantile levels }; enum enColorOn { cc_onSlope, // Change color on slope change cc_onMiddle, // Change color on middle line cross cc_onLevels // Change color on outer levels cross }; input ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT; // Time frame input int SzoPeriod = 14; // Sentiment zone period input enMaTypes SzoMethod = ma_tema; // Sentiment zone calculating method input enPrices Price = pr_close; // Price input int PriceFiltering = 14; // Price filtering period input enMaTypes PriceFilteringMethod = ma_sma; // Price filtering method input enColorOn ColorOn = cc_onLevels; // Color change input enLevelType LevelType = lvl_quan; // Level type input int LevelPeriod = 25; // Levels period input double LevelUp = 90.0; // Up level % input double LevelDown = 10.0; // Down level % input bool AlertsOn = false; // Turn alerts on? input bool AlertsOnCurrent = true; // Alert on current bar? input bool AlertsMessage = true; // Display messageas on alerts? input bool AlertsSound = false; // Play sound on alerts? input bool AlertsEmail = false; // Send email on alerts? input bool AlertsNotify = false; // Send push notification on alerts? input bool Interpolate = true; // Interpolate in multi time frame mode // // // // // double fill1[],fill2[],val[],valc[],levelUp[],levelMi[],levelDn[],count[],state[],prices[]; string _maNames[] = {"SMA","EMA","SMMA","LWMA","TEMA"}; int _mtfHandle = INVALID_HANDLE; ENUM_TIMEFRAMES timeFrame; #define _mtfCall iCustom(_Symbol,timeFrame,getIndicatorName(),PERIOD_CURRENT,SzoPeriod,SzoMethod,Price,PriceFiltering,PriceFilteringMethod,ColorOn,LevelType,LevelPeriod,LevelUp,LevelDown,AlertsOn,AlertsOnCurrent,AlertsMessage,AlertsSound,AlertsEmail,AlertsNotify) //------------------------------------------------------------------ // //------------------------------------------------------------------ // // // // // int OnInit() { SetIndexBuffer(0,fill1 ,INDICATOR_DATA); SetIndexBuffer(1,fill2 ,INDICATOR_DATA); SetIndexBuffer(2,levelUp,INDICATOR_DATA); SetIndexBuffer(3,levelMi,INDICATOR_DATA); SetIndexBuffer(4,levelDn,INDICATOR_DATA); SetIndexBuffer(5,val ,INDICATOR_DATA); SetIndexBuffer(6,valc ,INDICATOR_COLOR_INDEX); SetIndexBuffer(7,count ,INDICATOR_CALCULATIONS); SetIndexBuffer(8,prices ,INDICATOR_CALCULATIONS); for (int i=0; i<4; i++) PlotIndexSetInteger(i,PLOT_SHOW_DATA,false); timeFrame = MathMax(_Period,TimeFrame); IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(timeFrame)+" sentiment zone oscillator ("+(string)SzoPeriod+" "+_maNames[SzoMethod]+","+(string)PriceFiltering+" "+_maNames[PriceFilteringMethod]+")"); return(0); } //------------------------------------------------------------------ // //------------------------------------------------------------------ // // // // 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 (Bars(_Symbol,_Period) 0 && time[i-n] >= currTime[0]; n++) continue; for(k=1; (i-k)>=0 && k1) ? LevelPeriod : SzoPeriod; int i=(int)MathMax(prev_calculated-1,0); for (; i0) ? (prices[i]>prices[i-1]) ? 1 : (prices[i]levelUp[i]) ? 1 : (val[i]levelDn[i] && val[i]0) ? valc[i-1] : 0; break; case cc_onMiddle: valc[i] = (val[i]>levelMi[i]) ? 1 : (val[i]0) ? (val[i]>val[i-1]) ? 1 : (val[i]levelUp[i]) ? levelUp[i] : (val[i]=0; k++) _sortQuant[k] = _workQuant[i-k][instanceNo]; for (; k=0; k++) avg += workSma[r-k][instanceNo+0]; avg /= (double)k; return(avg); } // // // // // double workEma[][_maWorkBufferx1]; double iEma(double price, double period, int r, int _bars, int instanceNo=0) { if (ArrayRange(workEma,0)!= _bars) ArrayResize(workEma,_bars); workEma[r][instanceNo] = price; if (r>0 && period>1) workEma[r][instanceNo] = workEma[r-1][instanceNo]+(2.0/(1.0+period))*(price-workEma[r-1][instanceNo]); return(workEma[r][instanceNo]); } // // // // // double workSmma[][_maWorkBufferx1]; double iSmma(double price, double period, int r, int _bars, int instanceNo=0) { if (ArrayRange(workSmma,0)!= _bars) ArrayResize(workSmma,_bars); workSmma[r][instanceNo] = price; if (r>1 && period>1) workSmma[r][instanceNo] = workSmma[r-1][instanceNo]+(price-workSmma[r-1][instanceNo])/period; return(workSmma[r][instanceNo]); } // // // // // double workLwma[][_maWorkBufferx1]; double iLwma(double price, double period, int r, int _bars, int instanceNo=0) { if (ArrayRange(workLwma,0)!= _bars) ArrayResize(workLwma,_bars); workLwma[r][instanceNo] = price; if (period<1) return(price); double sumw = period; double sum = period*price; for(int k=1; k=0; k++) { double weight = period-k; sumw += weight; sum += weight*workLwma[r-k][instanceNo]; } return(sum/sumw); } // // // // // double workTema[][_maWorkBufferx3]; #define _tema1 0 #define _tema2 1 #define _tema3 2 double iTema(double price, double period, int r, int bars, int instanceNo=0) { if (ArrayRange(workTema,0)!= bars) ArrayResize(workTema,bars); instanceNo*=3; // // // // // workTema[r][_tema1+instanceNo] = price; workTema[r][_tema2+instanceNo] = price; workTema[r][_tema3+instanceNo] = price; if (r>0 && period>1) { double alpha = 2.0 / (1.0+period); workTema[r][_tema1+instanceNo] = workTema[r-1][_tema1+instanceNo]+alpha*(price -workTema[r-1][_tema1+instanceNo]); workTema[r][_tema2+instanceNo] = workTema[r-1][_tema2+instanceNo]+alpha*(workTema[r][_tema1+instanceNo]-workTema[r-1][_tema2+instanceNo]); workTema[r][_tema3+instanceNo] = workTema[r-1][_tema3+instanceNo]+alpha*(workTema[r][_tema2+instanceNo]-workTema[r-1][_tema3+instanceNo]); } return(workTema[r][_tema3+instanceNo]+3.0*(workTema[r][_tema1+instanceNo]-workTema[r][_tema2+instanceNo])); } //------------------------------------------------------------------ // //------------------------------------------------------------------ // // // // // void manageAlerts(const datetime& time[], double& trend[], int bars) { if (!AlertsOn) return; int whichBar = bars-1; if (!AlertsOnCurrent) whichBar = bars-2; datetime time1 = time[whichBar]; if (trend[whichBar] != trend[whichBar-1]) { if (trend[whichBar] == 1) doAlert(time1,"up"); if (trend[whichBar] == 2) doAlert(time1,"down"); } } // // // // // void doAlert(datetime forTime, string doWhat) { static string previousAlert="nothing"; static datetime previousTime; string message; if (previousAlert != doWhat || previousTime != forTime) { previousAlert = doWhat; previousTime = forTime; // // // // // message = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToString(TimeLocal(),TIME_SECONDS)+" sentiment zone oscillator state changed to "+doWhat; if (AlertsMessage) Alert(message); if (AlertsEmail) SendMail(_Symbol+" sentiment zone oscillator",message); if (AlertsNotify) SendNotification(message); if (AlertsSound) PlaySound("alert2.wav"); } } //------------------------------------------------------------------ // //------------------------------------------------------------------ // // // // // // #define _pricesInstances 1 #define _pricesSize 4 double workHa[][_pricesInstances*_pricesSize]; double getPrice(int tprice, const double& open[], const double& close[], const double& high[], const double& low[], int i,int _bars, int instanceNo=0) { if (tprice>=pr_haclose) { if (ArrayRange(workHa,0)!= _bars) ArrayResize(workHa,_bars); instanceNo*=_pricesSize; // // // // // double haOpen; if (i>0) haOpen = (workHa[i-1][instanceNo+2] + workHa[i-1][instanceNo+3])/2.0; else haOpen = (open[i]+close[i])/2; double haClose = (open[i] + high[i] + low[i] + close[i]) / 4.0; double haHigh = MathMax(high[i], MathMax(haOpen,haClose)); double haLow = MathMin(low[i] , MathMin(haOpen,haClose)); if(haOpen haOpen) return((haHigh+haClose)/2.0); else return((haLow+haClose)/2.0); case pr_hatbiased2: if (haClose>haOpen) return(haHigh); if (haCloseopen[i]) return((high[i]+close[i])/2.0); else return((low[i]+close[i])/2.0); case pr_tbiased2: if (close[i]>open[i]) return(high[i]); if (close[i]0) { CopyTime(_Symbol,_timeFrame,time[0],1,testTime); SeriesInfoInteger(_Symbol,_timeFrame,SERIES_FIRSTDATE,startTime); } if (startTime<=0 || startTime>time[0]) { Comment(MQL5InfoString(MQL5_PROGRAM_NAME)+"\nMissing data for "+timeFrameToString(_timeFrame)+" time frame\nRe-trying on next tick"); warned=true; return(false); } } if (warned) { Comment(""); warned=false; } return(true); }