//+------------------------------------------------------------------+ //| Kaufman's Adaptive Moving Average (KAMA).mq5 | //| Copyright © 2022, Centaur | //| https://www.mql5.com/en/users/centaur | //+------------------------------------------------------------------+ //--- proprietary #property copyright "Copyright © 2022, Centaur" #property link "https://www.mql5.com/en/users/centaur" #property version "1.00" //--- indicator description #property description " Type: Trend-Following Indicator" #property description "Description: KAMA is a moving average designed to account for market noise and / or volatility." #property description " KAMA will closely follow price when the price swings are relatively small and the noise" #property description " is low. KAMA will adjust when the price swings widen and will follow price from a greater" #property description " distance. (INCL. ATR BANDS)" #property description " Author: Perry Kaufman" #property description " Buffers: 0 - KAMA_LINE, 1 - UPPER_ATR_LINE, 2 - LOWER_ATR_LINE" //--- general indicator settings #property indicator_chart_window #property indicator_buffers 13 #property indicator_plots 3 //--- plot KAMA settings #property indicator_label1 "KAMA" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Upper ATR settings #property indicator_label2 "Upper ATR" #property indicator_type2 DRAW_LINE #property indicator_color2 clrOrange #property indicator_style2 STYLE_DOT #property indicator_width2 1 //--- plot Lower ATR settings #property indicator_label3 "Lower ATR" #property indicator_type3 DRAW_LINE #property indicator_color3 clrOrange #property indicator_style3 STYLE_DOT #property indicator_width3 1 //--- enumerations enum ENUM_PRICE_DERIVATIVE { Open, // Open High, // High Low, // Low Close, // Close Median, // Median, (h+l)/2 Mid, // Mid, (o+c)/2 Typical, // Typical, (h+l+c)/3 Weighted, // Weighted, (h+l+c+c)/4 Average // Average, (o+h+l+c)/4 }; //--- input parameters input group "KAMA Parameters:" input int inp_er_period = 10; // Efficiency Ratio Lookback Period input int inp_fast_ema_period = 2; // Fast EMA Lookback Period input int inp_slow_ema_period = 30; // Slow EMA Lookback Period input group "ATR Band Parameters:" input int inp_atr_period = 14; // ATR Band Lookback Period input double inp_atr_distance = 1.0; // ATR Band Distance Factor (Factor × ATR) input group "Price Parameters:" input ENUM_PRICE_DERIVATIVE inp_price = Close; // Price Derivative //--- indicator plot buffers double KAMAPlot[]; double UpperATRPlot[]; double LowerATRPlot[]; //--- indicator calculation buffers double prices[]; double TR[]; double ATR[]; double Change[]; double Volatility[]; double EfficiencyRatio[]; double SmoothingConstant[]; double KAMA[]; double UpperATR[]; double LowerATR[]; //--- variables int er_period; int fast_ema_period; int slow_ema_period; int atr_period; double atr_distance; double fast_alpha; double slow_alpha; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- check input parameters er_period = inp_er_period < 1 ? 1 : inp_er_period; fast_ema_period = inp_fast_ema_period < 1 ? 1 : inp_fast_ema_period; slow_ema_period = inp_slow_ema_period < inp_fast_ema_period ? inp_fast_ema_period + 1 : inp_slow_ema_period; atr_period = inp_atr_period < 1 ? 1 : inp_atr_period; atr_distance = inp_atr_distance < 0.5 ? 0.5 : inp_atr_distance; //--- indicator buffers mapping SetIndexBuffer(0, KAMAPlot, INDICATOR_DATA); SetIndexBuffer(1, UpperATRPlot, INDICATOR_DATA); SetIndexBuffer(2, LowerATRPlot, INDICATOR_DATA); SetIndexBuffer(3, prices, INDICATOR_CALCULATIONS); SetIndexBuffer(4, TR, INDICATOR_CALCULATIONS); SetIndexBuffer(5, ATR, INDICATOR_CALCULATIONS); SetIndexBuffer(6, Change, INDICATOR_CALCULATIONS); SetIndexBuffer(7, Volatility, INDICATOR_CALCULATIONS); SetIndexBuffer(8, EfficiencyRatio, INDICATOR_CALCULATIONS); SetIndexBuffer(9, SmoothingConstant, INDICATOR_CALCULATIONS); SetIndexBuffer(10, KAMA, INDICATOR_CALCULATIONS); SetIndexBuffer(11, UpperATR, INDICATOR_CALCULATIONS); SetIndexBuffer(12, LowerATR, INDICATOR_CALCULATIONS); //--- set indicator accuracy IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 1); //--- set indicator name display string short_name = "KAMA (" + string(er_period) + ", " + string(fast_ema_period) + ", " + string(slow_ema_period) + ", " + string(atr_period) + ", " + DoubleToString(atr_distance, 1) + ", " + EnumToString(inp_price) + ")"; IndicatorSetString(INDICATOR_SHORTNAME, short_name); //--- sets drawing lines to empty value PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE); //--- calculate fast and slow alpha's fast_alpha = 2.0 / (fast_ema_period + 1.0); slow_alpha = 2.0 / (slow_ema_period + 1.0); //--- 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[]) { //--- check period if(rates_total < er_period + fast_ema_period + slow_ema_period) return(0); //--- calculate start position int start_position; if(prev_calculated == 0) start_position = 0; else start_position = prev_calculated - 1; //--- main loop for(int i = start_position; i < rates_total && !_StopFlag; i++) { //--- populate price derivative buffer if(inp_price == Open) prices[i] = open[i]; if(inp_price == High) prices[i] = high[i]; if(inp_price == Low) prices[i] = low[i]; if(inp_price == Close) prices[i] = close[i]; if(inp_price == Median) prices[i] = (high[i] + low[i]) / 2; if(inp_price == Mid) prices[i] = (open[i] + close[i]) / 2; if(inp_price == Typical) prices[i] = (high[i] + low[i] + close[i]) / 3; if(inp_price == Weighted) prices[i] = (high[i] + low[i] + close[i] + close[i]) / 4; if(inp_price == Average) prices[i] = (open[i] + high[i] + low[i] + close[i]) / 4; //--- calculate true range buffer TR[i] = i < 1 ? high[i] - low[i] : fmax(high[i] - low[i], fmax(fabs(high[i] - close[i - 1]), fabs(low[i] - close[i - 1]))); //--- calculate average true range buffer ATR[i] = i < atr_period + 1 ? 0.0 : RMA(i, atr_period, ATR[i - 1], TR); //--- calculate price change buffer Change[i] = i < er_period + 1 ? 0.0 : fabs(prices[i] - prices[i - er_period]); //--- calculate price change volatility buffer if(i < 2 * er_period + 1) { Volatility[i] = 0.0; } else { double sum = 0.0; for(int j = 0; j < er_period; j++) { sum += Change[i - j]; } Volatility[i] = sum; } //--- calculate efficiency ratio buffer EfficiencyRatio[i] = i < 2 * er_period + 1 ? 0.0 : Change[i] / Volatility[i]; //--- calculate smoothing constant buffer SmoothingConstant[i] = i < 2 * er_period + 1 ? 0.0 : pow(EfficiencyRatio[i] * (fast_alpha - slow_alpha) + slow_alpha, 2); //--- calculate kaufman's adaptive moving average buffer KAMA[i] = i < 2 * er_period + 1 ? 0.0 : KAMA[i - 1] + SmoothingConstant[i] * (prices[i] - KAMA[i - 1]); //--- calculate upper average true range buffer UpperATR[i] = i < 2 * er_period + 1 ? 0.0 : KAMA[i] + atr_distance * ATR[i]; //--- calculate lower average true range buffer LowerATR[i] = i < 2 * er_period + 1 ? 0.0 : KAMA[i] - atr_distance * ATR[i]; //--- plot kaufman's adaptive moving average line KAMAPlot[i] = i < 2 * er_period + 1 ? EMPTY_VALUE : KAMA[i]; //--- plot upper average true range line UpperATRPlot[i] = i < 2 * er_period + 1 ? EMPTY_VALUE : UpperATR[i]; //--- plot lower average true range line LowerATRPlot[i] = i < 2 * er_period + 1 ? EMPTY_VALUE : LowerATR[i]; } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Function: Rolling (Smoothed) Moving Average (RMA) | //+------------------------------------------------------------------+ double RMA(const int position, const int period, const double prev_RMA_1_period_back, const double &price[]) { double result = 0.0; if(period > 0 && period <= (position + 1)) result = (prev_RMA_1_period_back * (period - 1) + price[position]) / period; return(result); } //+------------------------------------------------------------------+