//+-------------------------------------------------------------------------------------------------------+ //| Alpha Trend.mq5 | //| Copyright © 2022, Centaur | //| https://www.mql5.com/en/users/centaur | //| | //|For screenshots and extra info: | //| https://forex-station.com/viewtopic.php?p=1295492109&sid=16f4baa8018e53a3e71fb54b6b29977b#p1295492109 | //| | //+-------------------------------------------------------------------------------------------------------+ #property copyright "Copyright © 2022, Centaur" #property link "https://www.mql5.com/en/users/centaur" #property version "1.00" #property indicator_chart_window #property indicator_buffers 16 #property indicator_plots 3 //--- plot alpha line and offset line #property indicator_label1 "Alpha Line;Offset Line" #property indicator_type1 DRAW_FILLING #property indicator_color1 clrDodgerBlue,clrTomato #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Buy Signal #property indicator_label2 "Buy Signal" #property indicator_type2 DRAW_ARROW #property indicator_color2 clrDodgerBlue #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- plot Sell Signal #property indicator_label3 "Sell Signal" #property indicator_type3 DRAW_ARROW #property indicator_color3 clrTomato #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //--- enumerations enum ENUM_YES_NO { Yes, No }; //--- input parameters input int inp_length = 14; // Length input double inp_atr_multiplier = 1.0; // ATR Multiplier input ENUM_APPLIED_PRICE inp_price = PRICE_CLOSE; // Applied Price input ENUM_YES_NO inp_change_calc = No; // Use volume data ? input ENUM_YES_NO inp_signals = Yes; // Show Signals ? //--- indicator plot buffers double Alpha[]; double Offset[]; double Buy_Signal[]; double Sell_Signal[]; //--- indicator calculation buffers double TR[]; double ATR[]; double RSI[]; double MFI[]; double UpTrend[]; double DownTrend[]; double Alpha_Calc[]; double Buy_Signal_Calc[]; double Sell_Signal_Calc[]; double Buy_BarCount[]; double Sell_BarCount[]; double Arrows[]; //--- indicator variables int length; double atr_multiplier; int TR_Handle; int RSI_Handle; int MFI_Handle; string g_signal_prefix; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- check input parameters length = inp_length < 1 ? 1 : inp_length; atr_multiplier = inp_atr_multiplier < 0.1 ? 0.1 : NormalizeDouble(inp_atr_multiplier, 1); //--- indicator buffers mapping SetIndexBuffer(0, Alpha, INDICATOR_DATA); SetIndexBuffer(1, Offset, INDICATOR_DATA); SetIndexBuffer(2, Buy_Signal, INDICATOR_DATA); SetIndexBuffer(3, Sell_Signal, INDICATOR_DATA); SetIndexBuffer(4, TR, INDICATOR_CALCULATIONS); SetIndexBuffer(5, ATR, INDICATOR_CALCULATIONS); SetIndexBuffer(6, RSI, INDICATOR_CALCULATIONS); SetIndexBuffer(7, MFI, INDICATOR_CALCULATIONS); SetIndexBuffer(8, UpTrend, INDICATOR_CALCULATIONS); SetIndexBuffer(9, DownTrend, INDICATOR_CALCULATIONS); SetIndexBuffer(10, Alpha_Calc, INDICATOR_CALCULATIONS); SetIndexBuffer(11, Buy_Signal_Calc, INDICATOR_CALCULATIONS); SetIndexBuffer(12, Sell_Signal_Calc, INDICATOR_CALCULATIONS); SetIndexBuffer(13, Buy_BarCount, INDICATOR_CALCULATIONS); SetIndexBuffer(14, Sell_BarCount, INDICATOR_CALCULATIONS); SetIndexBuffer(15, Arrows, INDICATOR_CALCULATIONS); //--- set indicator accuracy IndicatorSetInteger(INDICATOR_DIGITS, _Digits); //--- set indicator name display string prices = inp_price == PRICE_OPEN ? "Open" : inp_price == PRICE_HIGH ? "High" : inp_price == PRICE_LOW ? "Low" : inp_price == PRICE_CLOSE ? "Close" : inp_price == PRICE_MEDIAN ? "Median" : inp_price == PRICE_TYPICAL ? "Typical" : inp_price == PRICE_WEIGHTED ? "Weighted" : " "; string short_name = "Alpha Trend (" + IntegerToString(length) + ", " + DoubleToString(atr_multiplier, 1) + ", " + prices + ", " + EnumToString(inp_change_calc) + ", " + EnumToString(inp_signals) + ")"; 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); PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE); //--- initialize buffers ArrayInitialize(Alpha, EMPTY_VALUE); ArrayInitialize(Offset, EMPTY_VALUE); ArrayInitialize(Buy_Signal, EMPTY_VALUE); ArrayInitialize(Sell_Signal, EMPTY_VALUE); ArrayInitialize(TR, 0.0); ArrayInitialize(ATR, 0.0); ArrayInitialize(RSI, 0.0); ArrayInitialize(MFI, 0.0); ArrayInitialize(UpTrend, 0.0); ArrayInitialize(DownTrend, 0.0); ArrayInitialize(Alpha_Calc, 0.0); ArrayInitialize(Buy_Signal_Calc, 0.0); ArrayInitialize(Sell_Signal_Calc, 0.0); ArrayInitialize(Buy_BarCount, 0.0); ArrayInitialize(Sell_BarCount, 0.0); ArrayInitialize(Arrows, 0.0); //--- setting a code from the Wingdings charset as the property of PLOT_ARROW PlotIndexSetInteger(1, PLOT_ARROW, 225); PlotIndexSetInteger(2, PLOT_ARROW, 226); //--- Set the vertical shift of arrows in pixels PlotIndexSetInteger(1, PLOT_ARROW_SHIFT, 20); PlotIndexSetInteger(2, PLOT_ARROW_SHIFT, -20); //--- create handles TR_Handle = iATR(_Symbol, _Period, 1); RSI_Handle = iRSI(_Symbol, _Period, length, inp_price); MFI_Handle = iMFI(_Symbol, _Period, length, VOLUME_TICK); if(TR_Handle == INVALID_HANDLE || RSI_Handle == INVALID_HANDLE || MFI_Handle == INVALID_HANDLE) return(INIT_FAILED); //--- scope signal keys by symbol, timeframe, and indicator inputs g_signal_prefix = StringFormat("AT_%s_%s_L%d_A%.1f_C%d_S%d", _Symbol, EnumToString(_Period), length, atr_multiplier, (int)inp_change_calc, (int)inp_signals); //--- initialization succeeded return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(TR_Handle != INVALID_HANDLE) IndicatorRelease(TR_Handle); if(RSI_Handle != INVALID_HANDLE) IndicatorRelease(RSI_Handle); if(MFI_Handle != INVALID_HANDLE) IndicatorRelease(MFI_Handle); } //+------------------------------------------------------------------+ //| 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(length <= 1 || length > rates_total) return(0); //--- latest data copy int copy; if(prev_calculated > rates_total || prev_calculated <= 0) copy = rates_total; else { copy = rates_total - prev_calculated; //--- last value is always copied copy++; } //--- populate buffers if(CopyBuffer(TR_Handle, 0, 0, copy, TR) <= 0) return(0); if(CopyBuffer(RSI_Handle, 0, 0, copy, RSI) <= 0) return(0); if(CopyBuffer(MFI_Handle, 0, 0, copy, MFI) <= 0) return(0); //--- calculate start position int bar; if(prev_calculated == 0) bar = 0; else bar = prev_calculated - 1; //--- main loop for(int i = bar; i < rates_total && !_StopFlag; i++) { if(i > length) { //--- calculate alpha trend ATR[i] = fSMA(i, length, TR); UpTrend[i] = low[i] - ATR[i] * atr_multiplier; DownTrend[i] = high[i] + ATR[i] * atr_multiplier; Alpha_Calc[i] = (inp_change_calc == No ? RSI[i] >= 50 : MFI[i] >= 50) ? UpTrend[i] < Alpha_Calc[i - 1] ? Alpha_Calc[i - 1] : UpTrend[i] : DownTrend[i] > Alpha_Calc[i - 1] ? Alpha_Calc[i - 1] : DownTrend[i]; //--- plot alpha trend Alpha[i] = NormalizeDouble(Alpha_Calc[i], _Digits); Offset[i] = NormalizeDouble(Alpha_Calc[i - 2], _Digits); //--- plot buy and sell signals Buy_Signal_Calc[i] = Alpha[i] > Offset[i] && Alpha[i - 1] <= Offset[i - 1] ? 1.0 : 0.0; Sell_Signal_Calc[i] = Alpha[i] < Offset[i] && Alpha[i - 1] >= Offset[i - 1] ? 1.0 : 0.0; Buy_BarCount[i] = fBarsSince(i, Buy_Signal_Calc); Sell_BarCount[i] = fBarsSince(i, Sell_Signal_Calc); Arrows[i] = Buy_BarCount[i] > Sell_BarCount[i] ? 1.0 : -1.0; Buy_Signal[i] = inp_signals == No ? EMPTY_VALUE : Arrows[i] == -1.0 && Arrows[i - 1] == 1.0 ? Offset[i] : EMPTY_VALUE; Sell_Signal[i] = inp_signals == No ? EMPTY_VALUE : Arrows[i] == 1.0 && Arrows[i - 1] == -1.0 ? Offset[i] : EMPTY_VALUE; } } //--- write only closed-bar signals to GlobalVariable for Mt5Bridge int last_closed = rates_total - 2; if(last_closed > length) { GlobalVariableSet(g_signal_prefix + "_Alpha", Alpha[last_closed]); GlobalVariableSet(g_signal_prefix + "_Offset", Offset[last_closed]); GlobalVariableSet(g_signal_prefix + "_Trend", Arrows[last_closed]); GlobalVariableSet(g_signal_prefix + "_Buy", Buy_Signal_Calc[last_closed]); GlobalVariableSet(g_signal_prefix + "_Sell", Sell_Signal_Calc[last_closed]); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+ //| Function: Simple Moving Average (SMA) | //+------------------------------------------------------------------+ double fSMA(const int _position, const int _period, const double &_input[]) { double result = 0.0; double sum = 0.0; for(int k = 0; k < _period; k++) sum += _input[_position - k]; result = sum / _period; return(result); } //+------------------------------------------------------------------+ //| Function: Count bars since last event greater than zero | //+------------------------------------------------------------------+ double fBarsSince(const int _position, const double &_input[]) { int result = 0; while(_position - result >= 0 && _input[_position - result] == 0.0) result++; return(result); } //+------------------------------------------------------------------+