//+------------------------------------------------------------------+ //| Chandelier Exit Arrows.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 6 #property indicator_plots 2 //--- plot Buy Signal #property indicator_label1 "Buy Signal" #property indicator_type1 DRAW_ARROW #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Sell Signal #property indicator_label2 "Sell Signal" #property indicator_type2 DRAW_ARROW #property indicator_color2 clrMagenta #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- input parameters input int inp_atr_period = 22; // ATR Period (min val: 1; step val: 1) input double inp_atr_multiplier = 3.0; // ATR Multiplier (min val: 0.1; step val: 0.1) input bool inp_use_close = true; // Use Close Price as Extremums? //--- indicator buffers double BuySignal[]; double SellSignal[]; double atr[]; double longStop[]; double shortStop[]; double dir[]; //--- indicator variables int atr_period; double atr_multiplier; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- check input parameters atr_period = inp_atr_period < 1 ? 1 : inp_atr_period; atr_multiplier = inp_atr_multiplier < 0.1 ? 0.1 : NormalizeDouble(inp_atr_multiplier, 1); //--- indicator buffers mapping SetIndexBuffer(0, BuySignal, INDICATOR_DATA); SetIndexBuffer(1, SellSignal, INDICATOR_DATA); SetIndexBuffer(2, atr, INDICATOR_CALCULATIONS); SetIndexBuffer(3, longStop, INDICATOR_CALCULATIONS); SetIndexBuffer(4, shortStop, INDICATOR_CALCULATIONS); SetIndexBuffer(5, dir, INDICATOR_CALCULATIONS); //--- setting a code from the Wingdings charset as the property of PLOT_ARROW PlotIndexSetInteger(0, PLOT_ARROW, 225); PlotIndexSetInteger(1, PLOT_ARROW, 226); //--- Set the vertical shift of arrows in pixels PlotIndexSetInteger(0, PLOT_ARROW_SHIFT, 15); PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, -15); //--- set indicator accuracy IndicatorSetInteger(INDICATOR_DIGITS, _Digits); //--- set indicator name display string bool_name = inp_use_close == true ? "True" : "False"; string short_name = "Chandelier Exit Arrows (" + IntegerToString(atr_period) + ", " + DoubleToString(atr_multiplier, 1) + ", " + bool_name + ")"; 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); //--- 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 ATR buffer inAverageTrueRange(rates_total, prev_calculated, atr_period, high, low, close, atr); //--- 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 < atr_period) { BuySignal[i] = EMPTY_VALUE; SellSignal[i] = EMPTY_VALUE; longStop[i] = 0.0; shortStop[i] = 0.0; dir[i] = 1.0; } else { double hh = -DBL_MAX, ll = DBL_MAX, atr_mult = atr_multiplier * atr[i]; for(int k = 0; k < atr_period; k++) { hh = inp_use_close == true ? (close[i - k] > hh ? close[i - k] : hh) : (high[i - k] > hh ? high[i - k] : hh); ll = inp_use_close == true ? (close[i - k] < ll ? close[i - k] : ll) : (low[i - k] < ll ? low[i - k] : ll); } longStop[i] = hh - atr_mult; longStop[i] = close[i - 1] > longStop[i - 1] ? fmax(longStop[i], longStop[i - 1]) : longStop[i]; shortStop[i] = ll + atr_mult; shortStop[i] = close[i - 1] < shortStop[i - 1] ? fmin(shortStop[i], shortStop[i - 1]) : shortStop[i]; dir[i] = close[i] > shortStop[i - 1] ? 1.0 : close[i] < longStop[i - 1] ? -1.0 : dir[i - 1]; BuySignal[i] = dir[i] == 1.0 && dir[i - 1] == -1.0 ? low[i] : EMPTY_VALUE; SellSignal[i] = dir[i] == -1.0 && dir[i - 1] == 1.0 ? high[i] : EMPTY_VALUE; } } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Average True Range (ATR) | //+------------------------------------------------------------------+ int inAverageTrueRange(const int rates_total, const int prev_calculated, const int value_length, const double &source_high[], const double &source_low[], const double &source_close[], double &result_atr[]) { //--- bar index start int bar_index; double alpha = 1.0 / double(value_length); 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++) { double true_range = i < 1 ? source_high[i] - source_low[i] : fmax(source_high[i] - source_low[i], fmax(fabs(source_high[i] - source_close[i - 1]), fabs(source_low[i] - source_close[i - 1]))); if(i < 1) result_atr[i] = true_range; else result_atr[i] = true_range * alpha + result_atr[i - 1] * (1.0 - alpha); } return(rates_total); } //+------------------------------------------------------------------+