//+------------------------------------------------------------------+ //| optimal tracking filter | //| mladen | //+------------------------------------------------------------------+ #property copyright "mrtools" #property link "mrtools@gmail.com" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 1 #property indicator_label1 "OTF" #property indicator_type1 DRAW_COLOR_LINE #property indicator_color1 clrDarkGray,clrOrangeRed,clrMediumSeaGreen #property indicator_width1 2 // // // input double inpPow = 2.0; // Default power = 2.0; input double inpSpeed1 = 16.0; // Default speed 1 = 16.0; input double inpSpeed2 = 8.0; // Default speed 2 = 8.0; input int inpSmooth = 5; // Price smoothing period enum enMaTypes { ma_ema, // Exponential moving average - EMA ma_lwma, // Linear weighted moving average - LWMA ma_sma, // Simple moving average - SMA ma_smma, // Smoothed moving average - SMMA }; input enMaTypes inpSmoothMode = ma_ema; // Price smoothing mode 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 pr_habclose, // Heiken ashi (better formula) close pr_habopen, // Heiken ashi (better formula) open pr_habhigh, // Heiken ashi (better formula) high pr_hablow, // Heiken ashi (better formula) low pr_habmedian, // Heiken ashi (better formula) median pr_habtypical, // Heiken ashi (better formula) typical pr_habweighted, // Heiken ashi (better formula) weighted pr_habaverage, // Heiken ashi (better formula) average pr_habmedianb, // Heiken ashi (better formula) median body pr_habtbiased, // Heiken ashi (better formula) trend biased price pr_habtbiased2 // Heiken ashi (better formula) trend biased (extreme) price }; input enPrices inpPrice = pr_median; // Price enum enColorOn { color_onSlo, // slope change color_onPrc // price cross }; input enColorOn inpColorOn = color_onSlo; // Color change on : double val[],valc[]; struct sGlobalStruct { double lam,alp; int lim,maSm; }; sGlobalStruct glo; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0,val ,INDICATOR_DATA); SetIndexBuffer(1,valc,INDICATOR_COLOR_INDEX); glo.maSm = fmax(inpSmooth,1); IndicatorSetString(INDICATOR_SHORTNAME," Optimal tracking filter"); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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[]) { glo.lim = (prev_calculated>0) ? prev_calculated-1 : 0; // // // struct sOtfStruct { double prc,tmp1,tmp2; }; static sOtfStruct wrk[]; static int wrkSize = -1; if (wrkSize0) ? 0.2*(wrk[i].prc-wrk[i-1].prc)+0.8*wrk[i-1].tmp1 : 0; wrk[i].tmp2 = (i>0) ? 0.1*(high[i]-low[i]) +0.8*wrk[i-1].tmp2 : 0; glo.lam = (wrk[i].tmp2!=0) ? fabs(wrk[i].tmp1/wrk[i].tmp2) : 0; glo.alp = (-pow(glo.lam,inpPow) + sqrt(pow(glo.lam,inpPow*2) + inpSpeed1*pow(glo.lam,inpPow)))/inpSpeed2; val[i] = (i>0) ? val[i-1]+glo.alp*(wrk[i].prc-val[i-1]) : wrk[i].prc; // // // if(inpColorOn==color_onSlo) valc[i] = (i>0) ? (val[i]>val[i-1]) ? 2 :(val[i]0) ? (val[i]wrk[i].prc) ? 1 : valc[i-1]: 0; } return(rates_total); } //-------------------------------------------------------------------------------------------------------------------------------------- // //-------------------------------------------------------------------------------------------------------------------------------------- string iGetAvgName(int method,bool returnShort=false) { switch(method) { case ma_ema: return(returnShort ? "EMA" : "Exponential moving average"); case ma_lwma: return(returnShort ? "LWMA" : "Linear weighted moving average"); case ma_sma: return(returnShort ? "SMA" : "Simple moving average"); case ma_smma: return(returnShort ? "SMMA" : "Smoothed moving average"); } return(""); } // // // #define _maInstances 1 double iCustomMa(int mode, double price, double length, int r, int bars, int instanceNo=0) { switch (mode) { case ma_sma : return(iSma(price,(int)ceil(length),r,bars,instanceNo)); case ma_ema : return(iEma(price,length,r,bars,instanceNo)); case ma_smma : return(iSmma(price,length,r,bars,instanceNo)); case ma_lwma : return(iLwma(price,(int)ceil(length),r,bars,instanceNo)); default : return(0); } } // // // double iSma(double price, double period, int r, int bars, int instanceNo=0) { struct sCoeffStruct { int period; bool recalc; sCoeffStruct() : period(INT_MIN) {} }; static sCoeffStruct m_coeffs[_maInstances]; struct sDataStruct { double price; double sum; double avg; int prevBar; sDataStruct() : prevBar(-1) {} }; struct sWorkStruct { sDataStruct data[_maInstances]; }; static sWorkStruct m_array[]; static int m_arraySize = -1; if (m_arraySize<=bars) m_arraySize = ArrayResize(m_array,bars+500,2000); if (m_coeffs[instanceNo].period != int(period)) { m_coeffs[instanceNo].period = period>1 ? (int)period : 1; m_coeffs[instanceNo].recalc = true; } // // // m_array[r].data[instanceNo].price = price; // // // if (m_array[r ].data[instanceNo].prevBar != r || m_array[r+1].data[instanceNo].prevBar >= r) { m_array[r ].data[instanceNo].prevBar = r; m_array[r+1].data[instanceNo].prevBar = -1; m_coeffs[instanceNo].recalc = true; } if (m_coeffs[instanceNo].recalc) { m_coeffs[instanceNo].recalc = false; m_array[r].data[instanceNo].sum = 0; for (int k=1; k=0; k++) m_array[r].data[instanceNo].sum += m_array[r-k].data[instanceNo].price; } return((m_array[r].data[instanceNo].sum + price)/(double)(r>=m_coeffs[instanceNo].period ? m_coeffs[instanceNo].period : r+1)); } // // // double iEma(double price, double period, int r, int bars, int instanceNo=0) { struct sDataStruct { double ema; }; struct sWorkStruct { sDataStruct data[_maInstances]; }; static sWorkStruct m_array[]; static int m_arraySize = -1; if (m_arraySize0 && period>1) m_array[r].data[instanceNo].ema = m_array[r-1].data[instanceNo].ema+(2.0/(1.0+period))*(price-m_array[r-1].data[instanceNo].ema); else m_array[r].data[instanceNo].ema = price; return(m_array[r].data[instanceNo].ema); } // // // double iSmma(double price, double period, int r, int bars, int instanceNo=0) { struct sDataStruct { double smma; }; struct sWorkStruct { sDataStruct data[_maInstances]; }; static sWorkStruct m_array[]; static int m_arraySize = -1; if (m_arraySize1) ? (int)period : 1; // // // if (r >= m_work[instanceNo].data[r].period && m_work[instanceNo].data[r-1].period == m_work[instanceNo].data[r].period && m_work[instanceNo].instancePeriod == m_work[instanceNo].data[r].period) { m_work[instanceNo].data[r].sum = m_work[instanceNo].data[r-1].sum + value - m_work[instanceNo].data[r-m_work[instanceNo].instancePeriod].value; m_work[instanceNo].data[r].sumValueWeight = m_work[instanceNo].data[r-1].sumValueWeight - m_work[instanceNo].data[r-1].sum + m_work[instanceNo].instancePeriod*value; } else { m_work[instanceNo].instancePeriod = m_work[instanceNo].data[r].period; m_work[instanceNo].instanceWeights = m_work[instanceNo].data[r].period; m_work[instanceNo].data[r].sumValueWeight = m_work[instanceNo].data[r].period*value; m_work[instanceNo].data[r].sum = value; // // // for(int k=1; k=k; k++) { double weight = m_work[instanceNo].instancePeriod-k; m_work[instanceNo].instanceWeights += weight; m_work[instanceNo].data[r].sumValueWeight += m_work[instanceNo].data[r-k].value*weight; m_work[instanceNo].data[r].sum += m_work[instanceNo].data[r-k].value; } } return(m_work[instanceNo].instanceWeights ? m_work[instanceNo].data[r].sumValueWeight/m_work[instanceNo].instanceWeights : value); } //-------------------------------------------------------------------------------------------------------------------------------------- // //-------------------------------------------------------------------------------------------------------------------------------------- template double iGetPrice(int tprice, T& open[], T& high[], T& low[], T& close[], int i, int bars) { if (tprice>=pr_haclose) { struct sHaStruct { double open; double high; double low; double close; }; static sHaStruct m_array[]; static int m_arraySize = -1; if (m_arraySize0) ? (m_array[r-1].open + m_array[r-1].close)/2.0 : (open[i]+close[i])/2;; double haClose = (open[i]+high[i]+low[i]+close[i]) / 4.0; #define _prHABF(_prtype) (_prtype>=pr_habclose && _prtype<=pr_habtbiased2) if (_prHABF(tprice)) if (high[i]!=low[i]) haClose = (open[i]+close[i])/2.0+(((close[i]-open[i])/(high[i]-low[i]))*MathAbs((close[i]-open[i])/2.0)); else haClose = (open[i]+close[i])/2.0; #undef _prHABF double haHigh = fmax(high[i], fmax(haOpen,haClose)); double haLow = fmin(low[i] , fmin(haOpen,haClose)); // // // if(haOpenhaOpen) return((haHigh+haClose)/2.0); else return((haLow+haClose)/2.0); case pr_hatbiased2: case pr_habtbiased2: 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]