//+------------------------------------------------------------------+ //| QBV.mq4 | //| extraw | //| http://www.forexfactory.com/extraw | //+------------------------------------------------------------------+ #property copyright "extraw" #property link "http://www.forexfactory.com/extraw" #property version "1.14" //option for filtering out overlap zone #property strict #property indicator_chart_window #property indicator_buffers 2 enum Style { Style_Solid = 0, //Solid Style_Dash = 1, //Dash Style_Dot = 2, //Dot Style_DashDot = 3, //DashDot Style_DashDotDot = 4 //DashDotDot }; enum Width { Width_1 = 1, //1 Width_2 = 2, //2 Width_3 = 3, //3 Width_4 = 4, //4 Width_5 = 5 //5 }; //--- input parameters input int PercentThreshold=50; input int N=50; // number of bars to calc average input color UpperBandColor=clrSkyBlue; input color LowerBandColor=clrDarkOrange; input Style BandStyle = 0; input Width BandWidth = 1; input bool Filter_Overlap_Zone = true; input bool NewZoneCreated_Alert = true; //--- variables double UpperBand[], LowerBand[]; string lineUpper, lineLower; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,UpperBand); SetIndexStyle(0,DRAW_LINE, BandStyle, BandWidth, UpperBandColor); SetIndexBuffer(1,LowerBand); SetIndexStyle(1,DRAW_LINE, BandStyle, BandWidth, LowerBandColor); IndicatorShortName("QBV(" + IntegerToString(PercentThreshold) + "%" + ") - " + IntegerToString(N) + " bars"); lineUpper = "[QBV]LineUpper_" + IntegerToString(PercentThreshold) + "_" + IntegerToString(N); ObjectCreate(0, lineUpper, OBJ_TREND, 0, 0, 0, 0, 0); ObjectSetInteger(0,lineUpper,OBJPROP_COLOR,UpperBandColor); ObjectSetInteger(0,lineUpper,OBJPROP_STYLE,BandStyle); ObjectSetInteger(0,lineUpper,OBJPROP_WIDTH,BandWidth); ObjectSetInteger(0,lineUpper,OBJPROP_BACK,false); ObjectSetInteger(0,lineUpper,OBJPROP_SELECTABLE,false); lineLower = "[QBV]LineLower_" + IntegerToString(PercentThreshold) + "_" + IntegerToString(N);; ObjectCreate(0, lineLower, OBJ_TREND, 0, 0, 0, 0, 0); ObjectSetInteger(0,lineLower,OBJPROP_COLOR,LowerBandColor); ObjectSetInteger(0,lineLower,OBJPROP_STYLE,BandStyle); ObjectSetInteger(0,lineLower,OBJPROP_WIDTH,BandWidth); ObjectSetInteger(0,lineLower,OBJPROP_BACK,false); ObjectSetInteger(0,lineLower,OBJPROP_SELECTABLE,false); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ 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[]) { //--- int counted_bars, limit; double volume_sum = 0, volume_avg = 0; double upper_value = 0, lower_value = 0; double upper_new = 0, lower_new = 0; counted_bars = IndicatorCounted(); if(counted_bars < 0) return(-1); //last counted bar will be recounted if(counted_bars > 0) counted_bars--; limit = Bars - counted_bars; if (limit < N) return(-2); // calc sum volume and avg volume of first 50 bars for(int i = limit - 1; i >= limit - 1 - N; i--) { volume_sum = volume_sum + Volume[i]; } volume_avg = volume_sum / N; //Begin the loop of calculations for the range of chart bars. for(int i = limit - 1 - N; i >= 0; i--) { if (Volume[i] > volume_avg + PercentThreshold / 100.0 * volume_avg) { upper_new = iHigh(NULL, 0, i); lower_new = iLow(NULL, 0, i); if (Filter_Overlap_Zone == true) { if (lower_new > upper_value || upper_new < lower_value) { upper_value = upper_new; lower_value = lower_new; // alert if this is last bar if (i == 0 && NewZoneCreated_Alert == true) Alert(Symbol() + " QBV(" + IntegerToString(PercentThreshold) + "%, " + IntegerToString(N) + "): New zone created"); } } else { upper_value = upper_new; lower_value = lower_new; // alert if this is last bar if (i == 0 && NewZoneCreated_Alert == true) Alert(Symbol() + " QBV(" + IntegerToString(PercentThreshold) + "%, " + IntegerToString(N) + "): New zone created"); } } UpperBand[i] = upper_value; LowerBand[i] = lower_value; // calc new sum and new avg volume_sum = volume_sum - Volume[i + N] + Volume[i]; volume_avg = volume_sum / N; } // draw lines beyond last bar ObjectMove(0, lineUpper, 0, Time[0], upper_value); ObjectMove(0, lineUpper, 1, Time[0] + PeriodSeconds(), upper_value); ObjectMove(0, lineLower, 0, Time[0], lower_value); ObjectMove(0, lineLower, 1, Time[0] + PeriodSeconds(), lower_value); //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Custor indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //---- string name; for (int i= ObjectsTotal(); i>=0; i--) { name = ObjectName(i); if (StringSubstr(name,0,5) == "[QBV]") ObjectDelete(name); } //---- return; } //+------------------------------------------------------------------+