#property copyright "Copyright S.Projects" #property link "http://trader.snowseed.com" #property indicator_separate_window #property indicator_buffers 1 #property indicator_color1 Red #property indicator_minimum 0 #property indicator_maximum 1 // indicator parameters extern int nClvPeriod = 27; extern int nClvMa = 7; // At the very beginning of the chart, before the MA // had enough data to draw itself properly, do not display int nDrawBeginBar; // indicator buffers double arrExtMapBuffer[]; // We are using this variable to store the number of bars // for which the chart is already drawn. The difference // between the total number of bars and this number is // the number of bars to draw (usually, 1) int nExtCountedBars = 0; //////////////////////// int init() { string strIndicatorShortName; strIndicatorShortName = "CLV(" + nClvPeriod + ", " + nClvMa + ")"; IndicatorShortName(strIndicatorShortName); // drawing settings SetIndexStyle(0, DRAW_LINE); SetIndexShift(0, 0); IndicatorDigits(4); // Skip drawing at the beginning of a chart nDrawBeginBar = MathMax(nClvPeriod, nClvMa); SetIndexDrawBegin(0, nDrawBeginBar); // indicator buffers mapping SetIndexBuffer(0, arrExtMapBuffer); return(0); } /////////////////////////// int start() { // Not enough points on a chart if(Bars <= nDrawBeginBar) return(0); // See if we have new data to plot (if a new tick came, // and it is the first tick of a new bar nExtCountedBars = IndicatorCounted(); if(nExtCountedBars < 0) return(-1); // Last counted bar will be recounted // Note, that here we force the last bar to be recounted. // You may comment this code, if you only want to do it // at the beginning of a new bar. I only keep this code // for compatibility with a little mess created by official // tutorials: see comment below (*) if(nExtCountedBars > 0) nExtCountedBars--; Clv(); return(0); } /////////////////// // For the selected period: // CLV = ((Close - Low) - (High - Close)) / (High - Low) void Clv() { // (*) Note the line below. If we use // "int nPos = Bars - nExtCountedBars;" the last bar // will be recounted every tick. If there is no "- 1", // only the beginning of a new bar triggers the code. int nPos = Bars - nExtCountedBars; // Note, that nPos is always > 0. It means, that Close[nPos] // is never Close[0], so we don't make a mistake by "looking // into the future". Note also, that we assign the value // to the arrExtMapBuffer[nPos]. It means, that when calling // this indicator from the expert, we need to use shift // >= 1. If we want to be able to call it with shift == 0, // we need to rewrite the code below, using // arrExtMapBuffer[nPos - 1]. The Close[...] and all other // functions obtaining data, should still use [nPos]. while(nPos > 0 && nPos < ArraySize(Low)) { double dClose = Close[nPos]; double dLow = Low[ArrayMinimum(Low, nClvPeriod, nPos)]; double dHigh = High[ArrayMaximum(High, nClvPeriod, nPos)]; arrExtMapBuffer[nPos] = 0; if(dHigh - dLow != 0) arrExtMapBuffer[nPos] = (((dClose - dLow) - (dHigh - dClose)) / (dHigh - dLow)) / 2 + 0.5; else arrExtMapBuffer[nPos] = 0; nPos--; } if(nClvMa > 1) Ema(arrExtMapBuffer); } /////////////////// void Ema(double& arr[]) { double dPr = 2.0 / (nClvMa + 1); int nPos = Bars - nExtCountedBars; while(nPos > 0) { if(nPos == Bars - 2) arrExtMapBuffer[nPos + 1] = arr[nPos + 1]; arrExtMapBuffer[nPos] = arr[nPos] * dPr + arrExtMapBuffer[nPos + 1] * (1 - dPr); nPos--; } } ///////////////////