//+------------------------------------------------------------------+ //| DPO_modified.mq5 | //| Copyright 2000-2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2000-2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.10" #property description "Detrended Price Oscillator - modified" #include //--- indicator settings #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 1 #property indicator_type1 DRAW_LINE #property indicator_color1 DodgerBlue #property indicator_levelstyle STYLE_DOT #property indicator_levelcolor DarkGray #property indicator_level1 0 //--- input parameters input int InpDetrendPeriod = 61; // DPO Period input ENUM_MA_METHOD MAmethod = MODE_SMA; // MA Method input ENUM_APPLIED_PRICE appliedprice = PRICE_CLOSE; // MA Applied price //--- indicator buffers double ExtDPOBuffer[]; double ExtMABuffer[]; double Extprice[]; int helpMABuffer; int ExtMAPeriod; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ void OnInit() { //--- get length of cycle for smoothing //ExtMAPeriod = InpDetrendPeriod / 2 + 1; ExtMAPeriod = InpDetrendPeriod; // change input period to equal MA period //--- indicator buffers mapping SetIndexBuffer(0, ExtDPOBuffer, INDICATOR_DATA); SetIndexBuffer(1, ExtMABuffer, INDICATOR_CALCULATIONS); SetIndexBuffer(2, Extprice, INDICATOR_CALCULATIONS); //--- set accuracy IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 1); //--- set first bar from what index will be drawn PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtMAPeriod - 1); //--- name for DataWindow and indicator subwindow label string short_name = StringFormat("modified DPO(%d)", InpDetrendPeriod); //--- set short name according to MA mode switch(MAmethod) { case MODE_EMA : short_name = short_name + " (EMA)"; break; case MODE_LWMA : short_name = short_name + " (LWMA)"; break; case MODE_SMA : short_name = short_name + " (SMA)"; break; case MODE_SMMA : short_name = short_name + " (SMMA)"; break; default : short_name = short_name; } IndicatorSetString(INDICATOR_SHORTNAME, short_name); } //+------------------------------------------------------------------+ //| Detrended Price Oscillator | //+------------------------------------------------------------------+ 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 start; int begin = 0; int first_index = begin + ExtMAPeriod - 1; //--- preliminary filling if(prev_calculated < first_index) { ArrayInitialize(ExtDPOBuffer, 0.0); start = first_index; if(begin > 0) PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, first_index); } else start = prev_calculated - 1; //---get price array if chosen MA applied price is PRICE_MEDIAN, PRICE_TYPICAL, or PRICE_WEIGHTED if(appliedprice >= 4)getLprice(rates_total, prev_calculated, begin, open, high, low, close, Extprice, appliedprice); //--- get MA buffer based on MA applied price and MA mode switch(appliedprice) { case PRICE_CLOSE : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, close, ExtMABuffer); break; case PRICE_OPEN : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, open, ExtMABuffer); break; case PRICE_HIGH : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, high, ExtMABuffer); break; case PRICE_LOW : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, low, ExtMABuffer); break; case PRICE_MEDIAN : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, Extprice, ExtMABuffer); break; case PRICE_TYPICAL : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, Extprice, ExtMABuffer); break; case PRICE_WEIGHTED : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, Extprice, ExtMABuffer); break; default : AverageOnArray(MAmethod, rates_total, prev_calculated, begin, ExtMAPeriod, close, ExtMABuffer); } //--- the main loop of calculations for(int i = start; i < rates_total && !IsStopped(); i++) ExtDPOBuffer[i] = close[i] - ExtMABuffer[i]; //--- OnCalculate done. Return new prev_calculated. return(rates_total); } //+------------------------------------------------------------------+ //| calculate average on array | //+------------------------------------------------------------------+ void AverageOnArray(const int mode, const int rates_total, const int prev_calculated, const int begin, const int period, const double& source[], double& destination[]) { switch(mode) { case MODE_EMA: ExponentialMAOnBuffer(rates_total, prev_calculated, begin, period, source, destination); break; case MODE_SMMA: SmoothedMAOnBuffer(rates_total, prev_calculated, begin, period, source, destination); break; case MODE_LWMA: LinearWeightedMAOnBuffer(rates_total, prev_calculated, begin, period, source, destination); break; default: SimpleMAOnBuffer(rates_total, prev_calculated, begin, period, source, destination); } } //+------------------------------------------------------------------+ //| get median , typical, & weighted prices (when requested) | //+------------------------------------------------------------------+ int getLprice(const int rates_total, const int prev_calculated, const int begin, const double &op[], const double &hi[], const double &lo[], const double &cl[], double &destination[], ENUM_APPLIED_PRICE Lprice) { bool as_series_destination=ArrayGetAsSeries(destination); ArraySetAsSeries(destination,false); int start_position = prev_calculated-1; if(start_position < 0){start_position = 0;} //--- main loop for(int i = start_position; i < rates_total; i++) { if(Lprice == PRICE_WEIGHTED)destination[i] = (hi[i] + lo[i] + cl[i] * 2) / 4; if(Lprice == PRICE_TYPICAL)destination[i] = (hi[i] + lo[i] + cl[i]) / 3; if(Lprice == PRICE_MEDIAN)destination[i] = (hi[i] + lo[i]) / 2; } ArraySetAsSeries(destination,as_series_destination); return rates_total; } //+------------------------------------------------------------------+