| //+------------------------------------------------------------------+
|
| //| NRTR Channel.mq5 |
|
| //| Copyright 2009-2025, MetaQuotes Ltd |
|
| //| https://www.mql5.com |
|
| //+------------------------------------------------------------------+
|
| #property copyright "2009-2025, MetaQuotes Ltd"
|
| #property link "http://www.mql5.com"
|
| #property description "NRTR Channel"
|
| //---
|
| #property indicator_chart_window
|
| #property indicator_buffers 6
|
| #property indicator_plots 4
|
| #property indicator_type1 DRAW_ARROW
|
| #property indicator_color1 clrDeepSkyBlue
|
| #property indicator_type2 DRAW_ARROW
|
| #property indicator_color2 clrDeepSkyBlue
|
| #property indicator_type3 DRAW_ARROW
|
| #property indicator_color3 clrLightSalmon
|
| #property indicator_type4 DRAW_ARROW
|
| #property indicator_color4 clrLightSalmon
|
| //--- labels
|
| #property indicator_label1 "Long Resistance"
|
| #property indicator_label2 "Long Support"
|
| #property indicator_label3 "Short Support"
|
| #property indicator_label4 "Short Resistance"
|
|
|
| //--- inputs
|
| input int InpATRPeriod=40; // ATR period
|
| input double InpkATR =2.0; // ATR multiplier
|
| input bool InpShowLabel=true; // show price of level
|
|
|
| //--- uptrend buffers
|
| double ExtCeilingBuffer[];
|
| double ExtBuyBuffer[];
|
| //--- downtrend buffers
|
| double ExtSellBuffer[];
|
| double ExtFloorBuffer[];
|
| //--- auxiliary buffers
|
| double ExtTrendBuffer[];
|
| double ExtATRBuffer[];
|
|
|
| //--- indicator handle
|
| int ExtATRHandle;
|
|
|
| #define UP_TREND 1
|
| #define DOWN_TREND -1
|
|
|
| //--- unique prefix for indicator objects
|
| string ExtPrefixUniq;
|
| //--- current chart scale
|
| long ExtChartScale=2;
|
| //--- price labels should not be shown on the built-in VPS
|
| bool ExtShowLabel=false;
|
| //+------------------------------------------------------------------+
|
| //| Custom indicator initialization function |
|
| //+------------------------------------------------------------------+
|
| int OnInit()
|
| {
|
| //--- if the indicator is running on the built-in VPS, price labels should not be shown
|
| if(!TerminalInfoInteger(TERMINAL_VPS))
|
| ExtShowLabel=InpShowLabel;
|
|
|
| //--- define buffers and plots
|
| SetIndexBuffer(0, ExtCeilingBuffer);
|
| PlotIndexSetInteger(0, PLOT_ARROW, 159);
|
|
|
| SetIndexBuffer(1, ExtBuyBuffer);
|
| PlotIndexSetInteger(1, PLOT_ARROW, 251);
|
|
|
| SetIndexBuffer(2, ExtSellBuffer);
|
| PlotIndexSetInteger(2, PLOT_ARROW, 251);
|
|
|
| SetIndexBuffer(3, ExtFloorBuffer);
|
| PlotIndexSetInteger(3, PLOT_ARROW, 159);
|
|
|
| SetIndexBuffer(4, ExtTrendBuffer, INDICATOR_CALCULATIONS);
|
| SetIndexBuffer(5, ExtATRBuffer, INDICATOR_CALCULATIONS);
|
|
|
| //--- indicator name
|
| IndicatorSetString(INDICATOR_SHORTNAME, "NRTR Channel");
|
| //--- number of digits of indicator value
|
| IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
|
|
|
| //---- Get the indicator handle
|
| ExtATRHandle=iATR(NULL, 0, InpATRPeriod);
|
|
|
| //--- prepare prefix for objects
|
| string number=StringFormat("%I64d", GetTickCount64());
|
| ExtPrefixUniq=StringSubstr(number, StringLen(number)-4);
|
| ExtPrefixUniq=ExtPrefixUniq+"_NRTR";
|
| Print("Indicator \"_NRTR Channel\" started, prefix=", ExtPrefixUniq);
|
|
|
| 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[])
|
| {
|
| //--- if the indicator has previously been calculated, start from the bar preceding the last one
|
| int start=prev_calculated-2;
|
|
|
| //--- if this is the first calculation of the indicator, set the calculation start and the trend direction
|
| if(prev_calculated==0)
|
| {
|
| start=InpATRPeriod;
|
| ArrayFill(ExtSellBuffer, 0, rates_total, EMPTY_VALUE);
|
| ArrayFill(ExtBuyBuffer, 0, rates_total, EMPTY_VALUE);
|
| ArrayFill(ExtCeilingBuffer, 0, rates_total, EMPTY_VALUE);
|
| ArrayFill(ExtFloorBuffer, 0, rates_total, EMPTY_VALUE);
|
| ArrayFill(ExtTrendBuffer, 0, rates_total, EMPTY_VALUE);
|
|
|
| //--- trend direction
|
| if(close[start-1]>low[start-1])
|
| {
|
| ExtTrendBuffer[start-1]=UP_TREND;
|
| ExtCeilingBuffer[start-1]=close[start-1];
|
| ExtBuyBuffer [start-1]=close[start-1]-InpkATR*ExtATRBuffer[start-1];
|
| }
|
| else
|
| {
|
| ExtTrendBuffer[start-1]=DOWN_TREND;
|
| ExtFloorBuffer[start-1]=close[start-1];
|
| ExtSellBuffer[start-1]=close[start-1]+InpkATR*ExtATRBuffer[start-1];
|
| }
|
| }
|
|
|
| //--- indicator values in the buffer
|
| if(CopyBuffer(ExtATRHandle, 0, 0, rates_total, ExtATRBuffer)<0)
|
| return(0);
|
|
|
| //--- calculate levels for all bars in a loop
|
| for(int i=start; i<rates_total; i++)
|
| {
|
| //--- if there was an uptrend on the previous bar
|
| if(ExtTrendBuffer[i-1]>0)
|
| {
|
| //--- if Low of the current bar is higher than the resistance level on the previous bar
|
| if(low[i]>ExtCeilingBuffer[i-1])
|
| {
|
| //--- update resistance levels
|
| ExtCeilingBuffer[i]=close[i]; // uptrend resistance level
|
| ExtFloorBuffer[i]=EMPTY_VALUE; // empty downtrend resistance level
|
| //--- update support levels
|
| ExtBuyBuffer[i]=close[i]-InpkATR*ExtATRBuffer[i];
|
| ExtSellBuffer[i]=EMPTY_VALUE;
|
| //--- set the sign of an uptrend on the current bar
|
| ExtTrendBuffer[i]=UP_TREND;
|
| continue;
|
| }
|
|
|
| //--- if closed lower than the previous-bar support level
|
| if(close[i]<ExtBuyBuffer[i-1])
|
| {
|
| ExtTrendBuffer[i]=DOWN_TREND; // downtrend
|
| //--- set levels for the downtrend
|
| ExtFloorBuffer[i]=close[i]; // resistance level
|
| ExtSellBuffer[i]=close[i]+InpkATR * ExtATRBuffer[i]; // support
|
| //--- delete uptrend levels
|
| ExtCeilingBuffer[i]=EMPTY_VALUE;
|
| ExtBuyBuffer[i]=EMPTY_VALUE;
|
| continue;
|
| }
|
| }
|
| else // if there was a downtrend on the previous bar
|
| {
|
| //--- if High of the current bar is lower than the resistance level on the previous bar
|
| if(high[i]<ExtFloorBuffer[i-1])
|
| {
|
| //--- update resistance levels
|
| ExtFloorBuffer[i]=close[i]; // downtrend resistance level
|
| ExtCeilingBuffer[i]=EMPTY_VALUE; // empty uptrend resistance level
|
| //--- update support levels
|
| ExtSellBuffer[i]=close[i]+InpkATR*ExtATRBuffer[i];
|
| ExtBuyBuffer[i]=EMPTY_VALUE;
|
| //--- set the sign of a downtrend on the current bar
|
| ExtTrendBuffer[i]=DOWN_TREND;
|
| continue;
|
| }
|
|
|
| //--- if closed higher than the previous-bar support level
|
| if(close[i]>ExtSellBuffer[i-1])
|
| {
|
| ExtTrendBuffer[i]=UP_TREND; // uptrend
|
| //--- set levels for the uptrend
|
| ExtCeilingBuffer[i]=close[i]; // resistance level
|
| ExtBuyBuffer[i]=close[i]-InpkATR*ExtATRBuffer[i]; // support
|
| //--- delete downtrend levels
|
| ExtFloorBuffer[i]=EMPTY_VALUE;
|
| ExtSellBuffer[i]=EMPTY_VALUE;
|
| continue;
|
| }
|
| }
|
|
|
| //--- if we reached this code line, the trend has not changed
|
| //--- so, copy the previous buffer values
|
| ExtSellBuffer[i] = ExtSellBuffer[i-1];
|
| ExtBuyBuffer[i] = ExtBuyBuffer[i-1];
|
| ExtCeilingBuffer[i]= ExtCeilingBuffer[i-1];
|
| ExtFloorBuffer[i] = ExtFloorBuffer[i-1];
|
| ExtTrendBuffer[i] = ExtTrendBuffer[i-1];
|
| }
|
|
|
| //--- draw labels on levels
|
| if(ExtShowLabel)
|
| {
|
| ShowPriceLevels(time[rates_total-1], rates_total-1);
|
| ChartRedraw();
|
| }
|
|
|
| //--- succesfully calculated
|
| return(rates_total);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Custom indicator deinitialization function |
|
| //+------------------------------------------------------------------+
|
| void OnDeinit(const int reason)
|
| {
|
| //--- delete all our graphical objects after use
|
| Print("Indicator \"NRTR Channel\" stopped, delete all objects with prefix=", ExtPrefixUniq);
|
| ObjectsDeleteAll(0, ExtPrefixUniq, 0, OBJ_ARROW_RIGHT_PRICE);
|
| ChartRedraw(0);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Handles CHARTEVENT_CHART_CHANGE to track chart window updates |
|
| //+------------------------------------------------------------------+
|
| void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
|
| {
|
| if(id==CHARTEVENT_CHART_CHANGE)
|
| if(!ChartGetInteger(0, CHART_SCALE, 0, ExtChartScale))
|
| {
|
| //--- output an error message to the Experts journal
|
| Print(__FUNCTION__+", ChartGetInteger(CHART_SCALE) failed, error = ", GetLastError());
|
| }
|
| //---
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Show prices' levels |
|
| //+------------------------------------------------------------------+
|
| void ShowPriceLevels(datetime time, int last_index)
|
| {
|
| color clr;
|
| double up, dn;
|
| //--- define color and levels
|
| if(ExtTrendBuffer[last_index]==UP_TREND)
|
| {
|
| clr=clrDeepSkyBlue;
|
| up=ExtCeilingBuffer[last_index];
|
| dn=ExtBuyBuffer[last_index];
|
| }
|
| else
|
| {
|
| clr=clrLightSalmon;
|
| up=ExtSellBuffer[last_index];
|
| dn=ExtFloorBuffer[last_index];
|
| }
|
|
|
| ShowRightPrice(ExtPrefixUniq+"_Res", time, up, clr);
|
| ShowRightPrice(ExtPrefixUniq+"_Sup", time, dn, clr);
|
| }
|
| //+------------------------------------------------------------------+
|
| //| Create or Update "Right Price Label" object |
|
| //+------------------------------------------------------------------+
|
| bool ShowRightPrice(const string name, datetime time, double price, color clr)
|
| {
|
| if(!ObjectCreate(0, name, OBJ_ARROW_RIGHT_PRICE, 0, time, price))
|
| {
|
| ObjectMove(0, name, 0, time, price);
|
| return(false);
|
| }
|
|
|
| //--- adjust label size based on chart scale
|
| int width=ExtChartScale>1 ? 2:1; // if chart scale > 1, then label size = 2
|
|
|
| ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
|
| ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
|
| ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
|
| ObjectSetInteger(0, name, OBJPROP_BACK, false);
|
| ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
|
| ObjectSetInteger(0, name, OBJPROP_SELECTED, false);
|
| ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
|
| ObjectSetInteger(0, name, OBJPROP_ZORDER, 0);
|
|
|
| return(true);
|
| }
|
| //+------------------------------------------------------------------+
|