//+------------------------------------------------------------------+ //| Moving Average Converging.mq5 | //| Copyright © 2023, Centaur | //| forex-station.com/memberlist.php?mode=viewprofile&u=4948703 | //+------------------------------------------------------------------+ #property copyright "Copyright © 2023, Centaur" #property link "forex-station.com/memberlist.php?mode=viewprofile&u=4948703" #property version "1.00" #property indicator_chart_window #property indicator_buffers 22 #property indicator_plots 1 //--- plot #property indicator_label1 "Fast MA; Converging MA" #property indicator_type1 DRAW_FILLING #property indicator_color1 clrDodgerBlue,clrMagenta #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- enumerations enum ENUM_RATES { ra_open, // Open ra_high, // High ra_low, // Low ra_close, // Close ra_median, // Median (h+l)/2 ra_typical, // Typical (h+l+c)/3 ra_weighted, // Weighted (h+l+c+c)/4 ra_average, // Average (o+h+l+c)/4 ra_medianb, // Median Body (o+c)/2 ra_trend_biased, // Trend Biased ra_trad_ha_open, // Traditional Heikin-Ashi Open ra_trad_ha_high, // Traditional Heikin-Ashi High ra_trad_ha_low, // Traditional Heikin-Ashi Low ra_trad_ha_close, // Traditional Heikin-Ashi Close ra_trad_ha_median, // Traditional Heikin-Ashi Median (hah+hal)/2 ra_trad_ha_typical, // Traditional Heikin-Ashi Typical (hah+hal+hac)/3 ra_trad_ha_weighted, // Traditional Heikin-Ashi Weighted (hah+hal+hac+hac)/4 ra_trad_ha_average, // Traditional Heikin-Ashi Average (hao+hah+hal+hac)/4 ra_trad_ha_medianb, // Traditional Heikin-Ashi Median Body (hao+hac)/2 ra_trad_ha_trend_biased, // Traditional Heikin-Ashi Trend Biased ra_mod_ha_open, // Modified Heikin-Ashi Open ra_mod_ha_high, // Modified Heikin-Ashi High ra_mod_ha_low, // Modified Heikin-Ashi Low ra_mod_ha_close, // Modified Heikin-Ashi Close ra_mod_ha_median, // Modified Heikin-Ashi Median (hah+hal)/2 ra_mod_ha_typical, // Modified Heikin-Ashi Typical (hah+hal+hac)/3 ra_mod_ha_weighted, // Modified Heikin-Ashi Weighted (hah+hal+hac+hac)/4 ra_mod_ha_average, // Modified Heikin-Ashi Average (hao+hah+hal+hac)/4 ra_mod_ha_medianb, // Modified Heikin-Ashi Median Body (hao+hac)/2 ra_mod_ha_trend_biased // Modified Heikin-Ashi Trend Biased }; //--- input parameters input int inp_period = 100; // Lookback Period input int inp_alpha_increment = 10; // Alpha Increment input int inp_fast_ma_denom = 10; // Fast MA Denominator input ENUM_RATES inp_rates = ra_close; // Applied Price //--- indicator buffers double fastma[]; double convergingma[]; double rates[]; double temp1[], temp2[], temp3[], temp4[], temp5[], temp6[], temp7[], temp8[], temp9[], temp10[], temp11[], temp12[], temp13[], temp14[], temp15[]; double upper[]; double lower[]; double init_ma[]; double alpha_arr[]; //--- indicator variables int period; int alpha_increment; int fast_ma_denom; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- check input parameters period = inp_period < 1 ? 1 : inp_period; alpha_increment = inp_alpha_increment < 1 ? 1 : inp_alpha_increment; fast_ma_denom = inp_fast_ma_denom < 1 ? 1 : inp_fast_ma_denom; //--- indicator buffers mapping SetIndexBuffer(0, fastma, INDICATOR_DATA); SetIndexBuffer(1, convergingma, INDICATOR_DATA); SetIndexBuffer(2, rates, INDICATOR_CALCULATIONS); SetIndexBuffer(3, temp1, INDICATOR_CALCULATIONS); SetIndexBuffer(4, temp2, INDICATOR_CALCULATIONS); SetIndexBuffer(5, temp3, INDICATOR_CALCULATIONS); SetIndexBuffer(6, temp4, INDICATOR_CALCULATIONS); SetIndexBuffer(7, temp5, INDICATOR_CALCULATIONS); SetIndexBuffer(8, temp6, INDICATOR_CALCULATIONS); SetIndexBuffer(9, temp7, INDICATOR_CALCULATIONS); SetIndexBuffer(10, temp8, INDICATOR_CALCULATIONS); SetIndexBuffer(11, temp9, INDICATOR_CALCULATIONS); SetIndexBuffer(12, temp10, INDICATOR_CALCULATIONS); SetIndexBuffer(13, temp11, INDICATOR_CALCULATIONS); SetIndexBuffer(14, temp12, INDICATOR_CALCULATIONS); SetIndexBuffer(15, temp13, INDICATOR_CALCULATIONS); SetIndexBuffer(16, temp14, INDICATOR_CALCULATIONS); SetIndexBuffer(17, temp15, INDICATOR_CALCULATIONS); SetIndexBuffer(18, upper, INDICATOR_CALCULATIONS); SetIndexBuffer(19, lower, INDICATOR_CALCULATIONS); SetIndexBuffer(20, init_ma, INDICATOR_CALCULATIONS); SetIndexBuffer(21, alpha_arr, INDICATOR_CALCULATIONS); //--- set indicator accuracy IndicatorSetInteger(INDICATOR_DIGITS, _Digits); //--- set indicator name display string rates_name = inp_rates == ra_open ? "Open" : inp_rates == ra_high ? "High" : inp_rates == ra_low ? "Low" : inp_rates == ra_close ? "Close" : inp_rates == ra_median ? "Median" : inp_rates == ra_typical ? "Typical" : inp_rates == ra_weighted ? "Weighted" : inp_rates == ra_average ? "Average" : inp_rates == ra_medianb ? "Median Body" : inp_rates == ra_trend_biased ? "Trend Biased" : inp_rates == ra_trad_ha_open ? "Trad HA Open" : inp_rates == ra_trad_ha_high ? "Trad HA High" : inp_rates == ra_trad_ha_low ? "Trad HA Low" : inp_rates == ra_trad_ha_close ? "Trad HA Close" : inp_rates == ra_trad_ha_median ? "Trad HA Median" : inp_rates == ra_trad_ha_typical ? "Trad HA Typical" : inp_rates == ra_trad_ha_weighted ? "Trad HA Weighted" : inp_rates == ra_trad_ha_average ? "Trad HA Average" : inp_rates == ra_trad_ha_medianb ? "Trad HA Median Body" : inp_rates == ra_trad_ha_trend_biased ? "Trad HA Trend Biased" : inp_rates == ra_mod_ha_open ? "Mod HA Open" : inp_rates == ra_mod_ha_high ? "Mod HA High" : inp_rates == ra_mod_ha_low ? "Mod HA Low" : inp_rates == ra_mod_ha_close ? "Mod HA Close" : inp_rates == ra_mod_ha_median ? "Mod HA Median" : inp_rates == ra_mod_ha_typical ? "Mod HA Typical" : inp_rates == ra_mod_ha_weighted ? "Mod HA Weighted" : inp_rates == ra_mod_ha_average ? "Mod HA Average" : inp_rates == ra_mod_ha_medianb ? "Mod HA Median Body" : inp_rates == ra_mod_ha_trend_biased ? "Mod HA Trend Biased" : " "; string short_name = "MA Converging (" + IntegerToString(period) + ", " + IntegerToString(alpha_increment) + ", " + IntegerToString(fast_ma_denom) + ", " + rates_name + ")"; IndicatorSetString(INDICATOR_SHORTNAME, short_name); //--- sets drawing lines to empty value PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); //--- initialization succeeded 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[]) { //--- populate rates buffer fuGetRates(rates_total, prev_calculated, inp_rates, open, high, low, close, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12, temp13, temp14, temp15, rates); //--- populate upper buffer fuHighestValue(rates_total, prev_calculated, period, high, upper); //--- populate lower buffer fuLowestValue(rates_total, prev_calculated, period, low, lower); //--- populate initial moving average buffer maSimple(rates_total, prev_calculated, period, rates, init_ma); //--- bar index start int bar_index; double factor = 1.0 / double (alpha_increment); if(prev_calculated == 0) bar_index = 0; else bar_index = prev_calculated - 1; //--- main loop for(int i = bar_index; i < rates_total && !_StopFlag; i++) { if(i < period) { fastma[i] = rates[i]; convergingma[i] = init_ma[i]; alpha_arr[i] = 0.0; } else { bool cross = (rates[i] > convergingma[i - 1] && rates[i - 1] < convergingma[i - 2]) || (rates[i] > convergingma[i - 1] && rates[i - 1] == convergingma[i - 2]) ? true : (rates[i] < convergingma[i - 1] && rates[i - 1] > convergingma[i - 2]) || (rates[i] < convergingma[i - 1] && rates[i - 1] == convergingma[i - 2]) ? true : false; alpha_arr[i] = cross ? 2.0 / (double(period) + 1.0) : rates[i] > convergingma[i - 1] && upper[i] > upper[i - 1] ? alpha_arr[i - 1] + factor : rates[i] < convergingma[i - 1] && lower[i] < lower[i - 1] ? alpha_arr[i - 1] + factor : alpha_arr[i - 1]; convergingma[i] = MathIsValidNumber(convergingma[i - 1] + alpha_arr[i - 1] * (rates[i] - convergingma[i - 1])) ? convergingma[i - 1] + alpha_arr[i - 1] * (rates[i] - convergingma[i - 1]) : init_ma[i]; fastma[i] = MathIsValidNumber(cross ? (rates[i] + fastma[i - 1]) / 2.0 : rates[i] > convergingma[i] ? fmax(rates[i], fastma[i - 1]) + (rates[i] - fastma[i - 1]) / fast_ma_denom : fmin(rates[i], fastma[i - 1]) + (rates[i] - fastma[i - 1]) / fast_ma_denom) ? (cross ? (rates[i] + fastma[i - 1]) / 2.0 : rates[i] > convergingma[i] ? fmax(rates[i], fastma[i - 1]) + (rates[i] - fastma[i - 1]) / fast_ma_denom : fmin(rates[i], fastma[i - 1]) + (rates[i] - fastma[i - 1]) / fast_ma_denom) : rates[i]; } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Get Rates from ENUM_RATES | //+------------------------------------------------------------------+ int fuGetRates(const int rates_total, const int prev_calculated, const ENUM_RATES list_rates, const double &source_open[], const double &source_high[], const double &source_low[], const double &source_close[], double &temp_trad_ha_open[], double &temp_trad_ha_high[], double &temp_trad_ha_low[], double &temp_trad_ha_close[], double &temp_mod_ha_open[], double &temp_mod_ha_high[], double &temp_mod_ha_low[], double &temp_mod_ha_close[], double &temp_e1[], double &temp_e2[], double &temp_e3[], double &temp_e4[], double &temp_e5[], double &temp_e6[], double &temp_mod_ha_close_calc[], double &result_rates[]) { //--- bar index start int bar_index; double alpha = 0.5; double c1 = -1.0; double c2 = 6.0; double c3 = -12.0; double c4 = 8.0; if(prev_calculated == 0) bar_index = 0; else bar_index = prev_calculated - 1; //--- main loop for(int i = bar_index; i < rates_total && !_StopFlag; i++) { temp_trad_ha_close[i] = (source_open[i] + source_high[i] + source_low[i] + source_close[i]) / 4.0; temp_trad_ha_open[i] = i < 1 ? (source_open[i] + source_close[i]) / 2 : (temp_trad_ha_open[i - 1] + temp_trad_ha_close[i - 1]) / 2; temp_trad_ha_high[i] = fmax(source_high[i], fmax(temp_trad_ha_open[i], temp_trad_ha_close[i])); temp_trad_ha_low[i] = fmin(source_low[i], fmin(temp_trad_ha_open[i], temp_trad_ha_close[i])); temp_mod_ha_close_calc[i] = MathIsValidNumber((source_open[i] + source_close[i]) / 2.0 + (((source_close[i] - source_open[i]) / (source_high[i] - source_low[i])) * fabs((source_close[i] - source_open[i]) / 2.0))) ? (source_open[i] + source_close[i]) / 2.0 + (((source_close[i] - source_open[i]) / (source_high[i] - source_low[i])) * fabs((source_close[i] - source_open[i]) / 2.0)) : (source_open[i] + source_high[i] + source_low[i] + source_close[i]) / 4.0; if(i < 1) { temp_e1[i] = temp_mod_ha_close_calc[i]; temp_e2[i] = temp_mod_ha_close_calc[i]; temp_e3[i] = temp_mod_ha_close_calc[i]; temp_e4[i] = temp_mod_ha_close_calc[i]; temp_e5[i] = temp_mod_ha_close_calc[i]; temp_e6[i] = temp_mod_ha_close_calc[i]; temp_mod_ha_close[i] = temp_mod_ha_close_calc[i]; temp_mod_ha_open[i] = (source_open[i] + source_close[i]) / 2.0; temp_mod_ha_high[i] = fmax(source_high[i], fmax(temp_mod_ha_open[i], temp_mod_ha_close[i])); temp_mod_ha_low[i] = fmin(source_low[i], fmin(temp_mod_ha_open[i], temp_mod_ha_close[i])); } else { temp_e1[i] = temp_mod_ha_close_calc[i] * alpha + temp_e1[i - 1] * (1.0 - alpha); temp_e2[i] = temp_e1[i] * alpha + temp_e2[i - 1] * (1.0 - alpha); temp_e3[i] = temp_e2[i] * alpha + temp_e3[i - 1] * (1.0 - alpha); temp_e4[i] = temp_e3[i] * alpha + temp_e4[i - 1] * (1.0 - alpha); temp_e5[i] = temp_e4[i] * alpha + temp_e5[i - 1] * (1.0 - alpha); temp_e6[i] = temp_e5[i] * alpha + temp_e6[i - 1] * (1.0 - alpha); temp_mod_ha_close[i] = c1 * temp_e6[i] + c2 * temp_e5[i] + c3 * temp_e4[i] + c4 * temp_e3[i]; temp_mod_ha_open[i] = (temp_mod_ha_open[i - 1] + temp_mod_ha_close[i - 1]) / 2.0; temp_mod_ha_high[i] = fmax(source_high[i], fmax(temp_mod_ha_open[i], temp_mod_ha_close[i])); temp_mod_ha_low[i] = fmin(source_low[i], fmin(temp_mod_ha_open[i], temp_mod_ha_close[i])); } switch(list_rates) { case ra_open: result_rates[i] = source_open[i]; break; case ra_high: result_rates[i] = source_high[i]; break; case ra_low: result_rates[i] = source_low[i]; break; case ra_close: result_rates[i] = source_close[i]; break; case ra_median: result_rates[i] = (source_high[i] + source_low[i]) / 2.0; break; case ra_medianb: result_rates[i] = (source_open[i] + source_close[i]) / 2.0; break; case ra_typical: result_rates[i] = (source_high[i] + source_low[i] + source_close[i]) / 3.0; break; case ra_weighted: result_rates[i] = (source_high[i] + source_low[i] + source_close[i] + source_close[i]) / 4.0; break; case ra_average: result_rates[i] = (source_high[i] + source_low[i] + source_close[i] + source_open[i]) / 4.0; break; case ra_trend_biased: if(source_close[i] > source_open[i]) result_rates[i] = (source_high[i] + source_close[i]) / 2.0; else result_rates[i] = (source_low[i] + source_close[i]) / 2.0; break; case ra_trad_ha_open: result_rates[i] = temp_trad_ha_open[i]; break; case ra_trad_ha_high: result_rates[i] = temp_trad_ha_high[i]; break; case ra_trad_ha_low: result_rates[i] = temp_trad_ha_low[i]; break; case ra_trad_ha_close: result_rates[i] = temp_trad_ha_close[i]; break; case ra_trad_ha_median: result_rates[i] = (temp_trad_ha_high[i] + temp_trad_ha_low[i]) / 2.0; break; case ra_trad_ha_medianb: result_rates[i] = (temp_trad_ha_open[i] + temp_trad_ha_close[i]) / 2.0; break; case ra_trad_ha_typical: result_rates[i] = (temp_trad_ha_high[i] + temp_trad_ha_low[i] + temp_trad_ha_close[i]) / 3.0; break; case ra_trad_ha_weighted: result_rates[i] = (temp_trad_ha_high[i] + temp_trad_ha_low[i] + temp_trad_ha_close[i] + temp_trad_ha_close[i]) / 4.0; break; case ra_trad_ha_average: result_rates[i] = (temp_trad_ha_high[i] + temp_trad_ha_low[i] + temp_trad_ha_close[i] + temp_trad_ha_open[i]) / 4.0; break; case ra_trad_ha_trend_biased: if(temp_trad_ha_close[i] > temp_trad_ha_open[i]) result_rates[i] = (temp_trad_ha_high[i] + temp_trad_ha_close[i]) / 2.0; else result_rates[i] = (temp_trad_ha_low[i] + temp_trad_ha_close[i]) / 2.0; break; case ra_mod_ha_open: result_rates[i] = temp_mod_ha_open[i]; break; case ra_mod_ha_high: result_rates[i] = temp_mod_ha_high[i]; break; case ra_mod_ha_low: result_rates[i] = temp_mod_ha_low[i]; break; case ra_mod_ha_close: result_rates[i] = temp_mod_ha_close[i]; break; case ra_mod_ha_median: result_rates[i] = (temp_mod_ha_high[i] + temp_mod_ha_low[i]) / 2.0; break; case ra_mod_ha_medianb: result_rates[i] = (temp_mod_ha_open[i] + temp_mod_ha_close[i]) / 2.0; break; case ra_mod_ha_typical: result_rates[i] = (temp_mod_ha_high[i] + temp_mod_ha_low[i] + temp_mod_ha_close[i]) / 3.0; break; case ra_mod_ha_weighted: result_rates[i] = (temp_mod_ha_high[i] + temp_mod_ha_low[i] + temp_mod_ha_close[i] + temp_mod_ha_close[i]) / 4.0; break; case ra_mod_ha_average: result_rates[i] = (temp_mod_ha_high[i] + temp_mod_ha_low[i] + temp_mod_ha_close[i] + temp_mod_ha_open[i]) / 4.0; break; case ra_mod_ha_trend_biased: if(temp_mod_ha_close[i] > temp_mod_ha_open[i]) result_rates[i] = (temp_mod_ha_high[i] + temp_mod_ha_close[i]) / 2.0; else result_rates[i] = (temp_mod_ha_low[i] + temp_mod_ha_close[i]) / 2.0; break; } } return(rates_total); } //+------------------------------------------------------------------+ //| Highest Value (HV) | //+------------------------------------------------------------------+ int fuHighestValue(const int rates_total, const int prev_calculated, const int value_length, const double &source_price[], double &result_hv[]) { //--- bar index start int bar_index; if(prev_calculated == 0) bar_index = 0; else bar_index = prev_calculated - 1; //--- main loop for(int i = bar_index; i < rates_total && !_StopFlag; i++) { if(i < value_length) result_hv[i] = EMPTY_VALUE; else { double hh = -DBL_MAX; for(int k = 0; k < value_length; k++) hh = source_price[i - k] > hh ? source_price[i - k] : hh; result_hv[i] = hh; } } return(rates_total); } //+------------------------------------------------------------------+ //| Lowest Value (LV) | //+------------------------------------------------------------------+ int fuLowestValue(const int rates_total, const int prev_calculated, const int value_length, const double &source_price[], double &result_lv[]) { //--- bar index start int bar_index; if(prev_calculated == 0) bar_index = 0; else bar_index = prev_calculated - 1; //--- main loop for(int i = bar_index; i < rates_total && !_StopFlag; i++) { if(i < value_length) result_lv[i] = EMPTY_VALUE; else { double ll = DBL_MAX; for(int k = 0; k < value_length; k++) ll = source_price[i - k] < ll ? source_price[i - k] : ll; result_lv[i] = ll; } } return(rates_total); } //+------------------------------------------------------------------+ //| Simple Moving Average (SMA) | //+------------------------------------------------------------------+ int maSimple(const int rates_total, const int prev_calculated, const int value_length, // min val: 1; step val: 1; default val: 10 const double &source_price[], double &result_sma[]) { //--- bar index start int bar_index; if(prev_calculated == 0) bar_index = 0; else bar_index = prev_calculated - 1; //--- main loop for(int i = bar_index; i < rates_total && !_StopFlag; i++) { if(i < value_length) result_sma[i] = source_price[i]; else { double sum = 0.0; for(int k = 0; k < value_length; k++) sum += source_price[i - k]; result_sma[i] = sum / double(value_length); } } return(rates_total); } //+------------------------------------------------------------------+