Hello,
I have several horizontal lines and trendlines in a chart and I want to check if any of them is within a defined price range. Right now I check all objects in a loop if any of them is between my price levels.
Is there another/easier possibility to check this without controlling all objects in a loop?
I only want to know if any of them is within my price range.
Could you please have a look at my code? If you plot a horizontal line to your chart and move it slowly with your mouse from top to bottom you will see some rectangles. These rectangles highlight Pinbars according to a very simple definition. But of course you see that in the code.
My problem here is the following: It takes pretty much processor-time to do all that and I would like to optimize the code. Maybe you have an idea how I can modify it to run faster? Right now it's ok but if I use this indicator in many different chart windows and when I scan for more patterns it might slow the computer down.
Here is my code. I am thankful for any small improvement.
//+------------------------------------------------------------------+ //| PinbarScanner.mq4 | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, MR" #property link "http://www.facebook.com/riemenschneider.marcus" #property version "1.00" #property strict #property indicator_chart_window extern int lineBuffer = 5; string ObjName; double line; int i, limit, end; bool PBL, PBS, PriceAtZone = false; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping for (int j = ObjectsTotal(); j >= 0; j--) { string name = ObjectName(j); if (StringFind(name, "[PAS]", 0) == 0) ObjectDelete(name); } //--- 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[]) { //--- limit = WindowFirstVisibleBar(); end = WindowBarsPerChart(); end = (int)MathMin(limit, end); for(i=limit; i>=end; i--) { //--- Pinbars PBL = MathMin(Open[i+1], Close[i+1]) - Low[i+1] >= 0.7*(High[i+1] - Low[i+1]); PBS = High[i+1] - MathMax(Open[i+1], Close[i+1]) >= 0.7*(High[i+1] - Low[i+1]); if (PBL || PBS) { for (int j = ObjectsTotal(); j >= 0; j--) { string name = ObjectName(j); line = 0; if (ObjectType(name) == OBJ_HLINE || ObjectType(name) == OBJ_TREND) { if (ObjectType(name) == OBJ_HLINE) line = ObjectGet(name, OBJPROP_PRICE1); else line = ObjectGetValueByShift(name, 0); double ZoneHi = line + lineBuffer*10*Point; double ZoneLo = line - lineBuffer*10*Point; if ((MathMax(High[i+1], High[i+2]) > ZoneLo && MathMin(Low[i+1], Low[i+2]) < ZoneLo) || (MathMax(High[i+1], High[i+2]) > ZoneHi && MathMin(Low[i+1], Low[i+2]) < ZoneHi)) { PriceAtZone = true; break; } else PriceAtZone = false; } } } if (PBL && PriceAtZone) { ObjName = "[PAS] Pinbar Long" + (string)Time[i+1]; ObjectCreate(0, ObjName, OBJ_RECTANGLE, 0, Time[i+2], High[i+1], Time[i], Low[i+1]); ObjectSet(ObjName, OBJPROP_COLOR, clrBlue); ObjectSet(ObjName, OBJPROP_BACK, false); } else ObjectDelete("[PAS] Pinbar Long" + (string)Time[i+1]); if (PBS && PriceAtZone) { ObjName = "[PAS] Pinbar Short" + (string)Time[i+1]; ObjectCreate(0, ObjName, OBJ_RECTANGLE, 0, Time[i+2], High[i+1], Time[i], Low[i+1]); ObjectSet(ObjName, OBJPROP_COLOR, clrRed); ObjectSet(ObjName, OBJPROP_BACK, false); } else ObjectDelete("[PAS] Pinbar Short" + (string)Time[i+1]); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
If there are N bars on chart (assuming not shifted) they are [limit .. limit - N+1] but you try to do [limit .. N] limit = WindowFirstVisibleBar(); end = WindowBarsPerChart(); end = (int)MathMin(limit, end); for(i=limit; i>=end; i--) {
Do your limits right int iLeft, iRight, double top, double bot; GetChartLimits(iLeft, iRight, top, bot); for(i=iLeft; i >= iRight; --i) { : void GetChartLimits(int&iLeft, int&iRight, double&top, double&bot,int iW=0){ top = WindowPriceMax(iW); iLeft = WindowFirstVisibleBar(); bot = WindowPriceMin(iW); iRight = iLeft-WindowBarsPerChart(); if(top-bot < pips2dbl) top = bot+pips2dbl; // Avoid scroll bug / div0 if(iRight < 0) iRight = 0; // Chart is shifted. } // GetChartLimits
- Why are you doing the above every tick? Nothing is changing on those bars.
- Just do it once.
int counted = IndicatorCounted(); int lookback = 2; // Max lookback "... High[i+2]) > ZoneLo..." for(i=Bars - 1 - MathMax(counted,lookback); i >= 1; --i) { // Don't do bar zero
- Or when a new bar forms
int OnCalculate(...) { static datetime Time0; if(Time0 == Time[0]) return; Time0 == Time[0]; :
- Or once per minute, giving the human time to move the lines
- Or when a line actually moves EventChartCustom - MQL4 Documentation
- Just do it once.
PBL = MathMin(Open[i+1], Close[i+1]) - Low[i+1] >= 0.7*(High[i+1] - Low[i+1]);
Why is everything i+1 or i+2? Do everything relative to i. You want to test if bar i is a PBelse line = ObjectGetValueByShift(name, 0);
You are testing bar i. Why are you getting the trendline location of bar zero?if ((MathMax(High[i+1], High[i+2]) > ZoneLo && MathMin(Low[i+1], Low[i+2]) < ZoneLo) || (MathMax(High[i+1], High[i+2]) > ZoneHi && MathMin(Low[i+1], Low[i+2]) < ZoneHi)) {
These calculations are not changing per object. Do them once, above the object loop.double H2 = MathMax(High[i+1], High[i+2]); double L2 = MathMin(Low[i+1], Low[i+2]); for (int j = ObjectsTotal(); j >= 0; j--) { : if ((H2 > ZoneLo && L2 < ZoneLo) || (H2 > ZoneHi && L2 < ZoneHi)) {
- That if tests for a candle intersecting ZoneLo or ZoneHi. What if the candle is inside the zone, (doesn't touch either?) You want to test if a candle intersects ZoneLo .. ZoneHi, simplify
bool isOutside = L2 > ZoneHi || H2 < ZoneLo; if(!isOutside) { // intersects.
Wow, a lot of great stuff... thank you very much for that! Some comments:
Generally I programmed this indicator because I am not interested in Pinbars, Outsidebars etc. when they are located somewhere in the chart. They are only important for me when appearing at a certain daily/weekly level. Earlier I just used a normal line-alert-indicator but I recognized that this alert is not important at all because then I still have to wait for a price action signal to place a trade. By the way, this is the reason I made the error with the trendline location at bar 0 instead of i. I copied this part from my line-alert-indicator.
I learned i+1 to use because the current bar 0 shouldn't be calclulated and I never questioned that. Now it's so simple by using i >= 1 instead of i >= 0 like I used to do all the time.
The code to be executed with every tick was just a test. Normally the code should be executed only once a new bar is printed. But I had to test if a signal appears (and disappears) when moving the line across the chart. This is the reason why I execute it every tick.
Before I fix my indicator now with the help of your code-fragments I want to ask you what exactly the & means in your GetChartLimits() function. What is the difference between int test and int&test ?
Thank you!
A last question.
What exactly is the difference between:
int counted = IndicatorCounted(); int lookback = 2; // Max lookback "... High[i+2]) > ZoneLo..." for(i=Bars - 1 - MathMax(counted,lookback); i >= 1; --i) { // Don't do bar zero
and
int OnCalculate(...) { static datetime Time0; if(Time0 == Time[0]) return; Time0 == Time[0]; :
As far as I know it does practically the same. The first part with IndicatorCounted() executes the code once for all bars and then it waits for a new bar to appear to do the next loop-calculation with just that single new bar. Is that generally correct? And the second option only executes the following code if a new bar is printed.
Can I also use them both together? My goal is the indicator to run once at the start and after that only when a new bar is printed. So I don't need it running at every tick.
![MQL5 - Language of trade strategies built-in the MetaTrader 5 client terminal](https://c.mql5.com/i/registerlandings/logo-2.png)
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Hello,
I have several horizontal lines and trendlines in a chart and I want to check if any of them is within a defined price range. Right now I check all objects in a loop if any of them is between my price levels.
Is there another/easier possibility to check this without controlling all objects in a loop?
I only want to know if any of them is within my price range.