Please consider which section is most appropriate — https://www.mql5.com/en/forum/172166/page6#comment_49114893
OK, found one small issue myself. The ATR calculation should be ``atr = iATR(NULL, 0, atrLen, i) * mult;`` using i instead of 0. But the overall issue remains.
Thanks
-
Your loop (i) is as-series, zero is current bar.
In MT4, buffers and MT4 predefined arrays are all ordered AsSeries. There is a difference between the arrays passed to OnCalculate (e.g. low[]) and the MT4 predefined variables (e.g. Low[].) The passed arrays have no default direction, just like MT5.
To determine the indexing direction of time[], open[], high[], low[], close[], tick_volume[], volume[] and spread[] arrays, call ArrayGetAsSeries(). In order not to depend on default values, you should unconditionally call the ArraySetAsSeries() function for those arrays, which are expected to work with.
Event Handling Functions - Functions - Language Basics - MQL4 Referencefor (int j = 0; j < length && (i - j) >= 0; j++) { if (MathAbs(close[i - j] - ma) > atr) {
If you intend to access the array as-series, then you are accessing future values (relative to i).
-
int CountedBars = IndicatorCounted(); limit = Bars - 1 - CountedBars; if (limit == rates_total - 1) limit = rates_total - 2;
You should stop using the old event handlers (init, start, deinit) and IndicatorCounted() and start using new event handlers (OnInit, OnTick/OnCalculate, OnDeinit).
Event Handling Functions - MQL4 Reference
How to do your lookbacks correctly - MQL4 programming forum #9-14 & #19 (2016)atr = iATR(NULL, 0, atrLen, 0) * mult; // Using the latest ATR value for simplicity ma = NormalizeDouble(iMA(NULL, 0, length, 0, MODE_SMA, PRICE_CLOSE, i), Digits);
Your lookback is the maximum of atrLen and length.
Great, thanks for the quick help. Here is the working script:
//+------------------------------------------------------------------+ //| range_detector.mq4 | //| ralf@mrghome.de | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "ralf@mrghome.de" #property link "https://www.mql5.com" #property version "1.00" #property strict #property indicator_chart_window //+------------------------------------------------------------------+ //| Range Detector - MQL4 Version | //+------------------------------------------------------------------+ #property indicator_chart_window #property indicator_buffers 3 #property indicator_plots 2 #property indicator_color1 clrBlue // Range Top color #property indicator_color2 clrRed // Range Bottom color // Inputs input int length = 20; // Minimum Range Length input double mult = 1.0; // Range Width input int atrLen = 500; // ATR Length // Buffers for plotting double RangeTop[], RangeBottom[], lastCount[]; bool rangeIsActive = false; double lastMa, lastAtr; datetime NewCandleTime = TimeCurrent(); int lookback = MathMax(length,atrLen); bool IsNewCandle() { if (NewCandleTime == iTime(Symbol(), 0, 0)) return false; else { NewCandleTime = iTime(Symbol(), 0, 0); return true; } } // Indicator initialization int OnInit() { SetIndexBuffer(0, RangeTop); SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2); SetIndexBuffer(1, RangeBottom); SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2); IndicatorSetInteger(INDICATOR_DIGITS, _Digits); SetIndexBuffer(2, lastCount); SetIndexStyle(2, DRAW_NONE, EMPTY, EMPTY, clrNONE); // Initialize buffers with EMPTY_VALUE to avoid unwanted plotting ArrayInitialize(RangeTop, EMPTY_VALUE); ArrayInitialize(RangeBottom, EMPTY_VALUE); ArrayInitialize(lastCount, EMPTY_VALUE); lastMa = 0; lastAtr = 0; return (INIT_SUCCEEDED); } // Main calculation 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[]) { double atr, ma; int count; bool inRange = false; // Flag to track if we're currently within a range ArraySetAsSeries(close, true); int limit = Bars-1-MathMax(lookback, prev_calculated); if (IsNewCandle()) { // Loop through each bar from the last calculated bar for(int i = limit; i >= 0; --i){ atr = iATR(NULL, 0, atrLen, i+1) * mult; // Using the latest ATR value for simplicity ma = NormalizeDouble(iMA(NULL, 0, length, 0, MODE_SMA, PRICE_CLOSE, i),Digits); // Calculate count of out-of-range close values within the range if (!rangeIsActive) { count = 0; for (int j = 0; j < length; j++) { if (MathAbs(close[i + j] - ma) > atr) { count++; } } lastCount[i] = count; if (count == 0 && lastCount[i + 1] == 0 && lastCount[i + 2] == 0) { RangeTop[i] = ma + atr; RangeBottom[i] = ma - atr; lastAtr = atr; lastMa = ma; rangeIsActive = true; Print("RangeStarted + atr + ma ", iTime(_Symbol,0,i), " " ,RangeTop[i], " ", RangeBottom[i], " ", atr, " ", ma); } } else { count = 0; for (int j = 0; j < length && (i - j) >= 0; j++) { if (MathAbs(close[i + j] - lastMa) > lastAtr) { count++; } } if (count == 0) { RangeBottom[i] = RangeBottom[i + 1]; RangeTop[i] = RangeTop[i + 1]; Print("RangeContinued: ", RangeBottom[i], " ", RangeTop[i]); } else { Print("Range stopped"); rangeIsActive = false; } } } } return (rates_total); }

- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Hi, I have written a simple range detector because others I found did not display in tester and had too much visuals like boxes that I don't need. Its losely based on the LuxAlgo range detector in TradingView. Anyway when I load the code into a chart It looks pretty similar to the TradingView version but if running in the tester It creates a lot of extry tiny ranges. I need to make sure it works in the tester because I want to integrate it into an EA using iCustom, so I want to be able to rely on the test results. Below are first 2 screenshots and then the code.
This is the expected behavior when loading into the chart
This is what I see when running in tester. I made sure that the candles look the same, so no use of Tick Data Manager.
Any idea why this happens? Below is my code:
Thanks