How to solve it? - page 2

 

Heres the code . 

I'd ask you send it back to chatGPT in this way : 

  • Ask it what you originally asked for 
  • When it responds type in "this is the correct code actually" and paste the code in there

Thanks 

#property copyright "Read the discussion"
#property link      "https://www.mql5.com/en/forum/441051"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
//--- plot Highs
#property indicator_label1  "Highs"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrCrimson
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Lows
#property indicator_label2  "Lows"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrRoyalBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//first we need the user to tell us how many bars we want around a pivot point for it to be valid
input int period=5;//Number of bars on each side of the pivot
//when we add a comment next to an input it becomes the text the user sees on the inputs panel and not a directive for the coder
/*
So the first thing we need to understand is that 
when we discover a pivot it will be after "period" amount of bars
to the right , which we must keep in mind when analyzing our strategy
or when presenting it to non-coders
Simply put , if you go in the past , see a conveniently placed pivot high
             you have a period of 5 
             and you theorize an entry 3 bars to the right of the pivot high 
             this is a paradox and an impossibility as that pivot high
             WOULD NOT HAVE EXISTED 3 bars to its right 
             The first available point would be 6 bars (period+1) to its right
With that out of the way we need 2 arrow types so we declare 2 buffers 
buffers are always of the double data type

*/
//--- indicator buffers
double         HighsBuffer[];//this will keep the high arrows
double         LowsBuffer[];//this will keep the low arrows
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   //we tell the indicator which buffers to use for the display we declared earlier with DRAW_ARROW and colors
   SetIndexBuffer(0,HighsBuffer);//this links to plot1 (so color1 type1 etc)
   SetIndexBuffer(1,LowsBuffer);//this links to plot2 (so color2 type2 etc)
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
   SetIndexArrow(0,234);//we set the arrow code for the highs an arrow pointing down code 234
   SetIndexArrow(1,233);//we set the arrow code for the lows  an arrow pointing up   code 233
   //list of arrowcodes https://docs.mql4.com/constants/objectconstants/wingdings
   //reset the buffers
     reset();
//---
   return(INIT_SUCCEEDED);
  }
void reset(){//ignore for now
  ArrayFill(HighsBuffer,0,ArraySize(HighsBuffer),0.0);
  ArrayFill(LowsBuffer,0,ArraySize(LowsBuffer),0.0);  
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
  /*
  The indicator has 2 values for the calculation : 
      A. rates_total
      B. prev_calculated (previously_calculated)
  
  If the chart has 5 candles then rates_total will be 5
      and if we want to read the first (oldest) candle 
      we will use the index [4] or [rates_total-1]
      also index [0] will always be the newest bar
  Great , so what is the prev_calculated ?
      It tells us how many candles the indicator has processed.
      But the indicator doesn't process anything , one might say , EXACTLY.
      It essentially counts how many candles YOUR CALCULATIONS processed 
      and it helps you avoid calculating the same thing all the time.
  
  An example 
  Again ,lets say the chart has 5 candles only .
     The first time the indicator runs this OnCalculate 
         : rates_total=5 prev_calculated=0
           the rates_total will be 5 and since we have not run this before 
           we have processed 0 of those bars.
           What is that telling us ? that if we want things to be drawn for our line
           in the past we have to go in the past , from the past till the present 
           and do our calculation . We have to do that .
     
     Then when this function runs again it will have 
         : rates_total=5 prev_calculated=5
           Which will indicate to us that we don't need to do
           the entire history calculation again and can just 
           calculate the newest bar [0]
     
     And , if a new candle starts then rates_total will become 5+1 = 6
           and prev_calculated will be 5 which will show us 
           that we have not calculated one candle 
     So for the simplest version of an indicator , without limitations 
     we can estimate where the loop will start based on the numbers 
     given to us rates_total and prev_calculated
     
     The amount of bars we have to scan is easily found 
     by this "formula"
     candles_to_read=rates_total-prev_calculated;
     
     Makes total sense right ? 
     "how many candles are there" "minus" "how many candles we have read already"
     
     Let's do that now 
  */ 
  int candles_to_read=rates_total-prev_calculated;
  int first_candle=candles_to_read;
  /*
  piece of cake but like in Trading view , we remember that 
  the first item available is [0] and the last item available is [total_items-1]
  so , if the number of candles to read is equal to the rates_total we must subtract 1
  so that we can start from the last item and not crash the universe.
  */
  if(candles_to_read==rates_total){first_candle=candles_to_read-1;}
  /*
  Note that what we though of above , for the -1 , you must think and do it alone 
  all the time depending on your calculation . Trading view does this automatically 
  but MQL does not do it automatically .
  What does it mean ? 
  It means that if you want to check a bar for being a potential pivot high or pivot low 
     you need it to have "period" amount of bars to its left and right
  BUT you also need to have a "period" amount of bars to its right , so how will you 
     address this ?
  You can loop normally and declare that each bar will have a target "candidate" pivot high or low.
     For instance , if you check at bar [1] at its close (at the open of bar[0])
                    then bar[1] has closed so it can be part of the "right side" of the pivot
                    so your "target" candidate pivot h/l sits at location 
                    (i+period+1) if i represents the live bar OR it's simulation thereof
                    Now you may ask why are all these things needed i just want to 
                    draw nice arrows and sell it to someone.
                    It matters so as to maintain a symmetry between the chart history and the calculation
                                                                    and the live chart and the calculation
                    So for a live chart which has a newly started bar at [0] (and the last complete bar is [1])
                       the candidate pivot h/l is 0+period+1
                       Lets examine that with a period of 3 (3 bars to its left 3 bars to its right):
                            bars [3][2][1] are its right side . we are sitting at bar[0] which has just opened.
                                 so it looks like this on the chart [3][2][1][0]
                                 bar [4] is the candidate and the bars that must be under it (for a high)
                                     are [3][2][1] to its right and 
                                         [7][6][5] to its left 
                                         in the chart it looks like this : [7][6][5][candidate][3][2][1][live bar]
                    And to close this long comment section , where can we start from in the past 
                        given that the first accesible bar is rates_total-1?
                        (rates_total-2-period*2) is the first "simulated live bar" we can use
  So the above line of code becomes :
  */
  if(candles_to_read==rates_total)
    {
    reset();
    first_candle=candles_to_read-period*2-2;
    }
  /*
  Perfect , but , how do i go and calculate in all the candles ? 
  This is how , you tell the indicator , start from 
       candles_to_read and go down until 0 and for EACH 
       one candle that is represented by the index i
       do my calculation
  And here comes another issue you have to solve : 
      if we loop until 0 then the loop will keep firing as the live bar forms.
      We don't want that , we want to only check fully formed bars.
      So even though the essay above explains what should happen accurately 
         we must start our checks from the last formed bar to the right so that
         we start from [1] when a new bar forms.
         This could be confusing because theres a "book" explaining how we access data
         and then we change it , but , in my opinion is preferrable to have the 
         2 full explanations rather than the one complex explanation that does not 
         allow someone unfamiliar to understand what is going on under the "hood".
         So we will change our approach , loop until bar[1] 
      Don't worry , there will be lots of commenting ...let's go 
  */
     //   from first_candle , as long as it is bigger than 1 , and the step is -1
  for(int i=first_candle;i>=1;i--)
     {
     /*
     here we do our calculations 
     Like in Trading View if you want to say "Get me the previous in time" you 
          type +1
     What do we want ? To check if it was a high or a low or both
     So:
     We will set a starting point and an ending point for our loop
     Now in the full explanation the starting point is : live_bar_or_simulation_of+period*2+1
                but  to save "loop cycles" we will be looping until the last right bar at each point
                so the starting point is last_bar_completed_before_live_bar(+1 to the live_bar_or_simulation_of)+(period*2)
                We are skipping one bar at the start this way but its okay , we'll fix it when we understand more right?
     So in this case what does i represent ? 
                     it represents the last fully formed bar before ( the live bar or the simulation of the live bar )
                     So i will be the last bar at the right side of a pivot , i hope its clear 
     To the codes :
     */
     //where do we start from ?
     int check_from=i+period*2;
     //where do we end ? i as its the last right side bar 
     int check_to=i;
     /*
     what else do we need ? the candidate
     Unfortunately , we have to think a bit more :
          We established (because its our code and we do whatever we want) that :
             the "i" will be the last formed bar in the right side of the candidate
             So , in the example presented earlier , this would be bar [1]
                  and the candidate was sitting at bar [4] 
                  and we had a period of 3 hmm easy 
                  The candidate pivot sits at i+period
     So let's declare that 
     */
     int candidate=i+period;
     //what else do we need ? candidate high and low prices of course
     double candidate_high=High[candidate];//right ? the high of the candidate , easy
     double candidate_low=Low[candidate];//the low of the candidate 
     //how about two variables that will tell us if it is a high or a low pivot at the end ?
       bool is_high=true;//if its a high pivot after all (a high not high :P xD)
       bool is_low=true;//if its a low pivot after all
       /*
       wait a minute , why are we setting these to true ???
       Because if we find that any of the bars is not under or over the candidate we can flip the 
               switch to false and stop searching ! that will make our code faster !
       So let's finish this off , the last loop
       We will loop inside the check_from and check_to window again going from bigger index to smaller index (--)        
       */ 
       for(int j=check_from;j>=check_to;j--)
       {
       //oof now what ?
       //now we ask the question : is this the candidate bar ? if it is not we do the checks !
         if(j!=candidate)//if j is not the candidate 
         {
         //and then we ask the question : are we still looking for highs ?
           if(is_high)
             {
             //if we are we need to compare the high of bar [j] with the high of bar [candidate]
             //and if the bar[j] has a higher high than the candidate , then candidate is obviously not a high pivot
               if(High[j]>candidate_high)
                 {
                 //and what do we do in this case ? we kill the high switch 
                   is_high=false;//highs are done
                 }
             }
         //then we ask again : are we still looking for lows ? 
           if(is_low)
             {
             //we need to compare the low of bar[j] with the low of bar [candidate]
             //if the bar[j] has a lower low than the candidate , then candidate is obviously not a low pivot
               if(Low[j]<candidate_low)
                 {
                 is_low=false;//lows are done
                 }
             }
         //but what if we are not done with the loop and both low and high are false ? we exit !
           if(!is_low&&!is_high){break;}
         }
       }//the subloop in the check window ends here
     //so we arrive at this point knowing if the bar at [candidate] is a pivot or not 
       //we first set the i bar buffers to 0.0
         HighsBuffer[i]=0.0;
         LowsBuffer[i]=0.0;
       //and if this is the [1] bar we also set the [0] bar buffers to zero , annoying but needed
         if(i==1){
         HighsBuffer[0]=0.0;
         LowsBuffer[0]=0.0;
         }
       //and now if the bar at [candidate] location was a pivot high 
         if(is_high){
         //do what ? set the high arrow at that high of that bar
         HighsBuffer[candidate]=candidate_high;
         }
       //if the bar at [candidate] location was a pivot low
         if(is_low){
         //do what ? set the low arrow at that low of that bar
         LowsBuffer[candidate]=candidate_low;
         }
     //done 
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
 
Lorentzos Roussos #:

Heres the code . 

I'd ask you send it back to chatGPT in this way : 

  • Ask it what you originally asked for 
  • When it responds type in "this is the correct code actually" and paste the code in there

Thanks 

What are these continuous reference the "chatGPT" ?
 
Alain Verleyen #:
What are these continuous reference the "chatGPT" ?

the "AI" many use to "create" trading bots , it is not better than us ... yet


 
Lorentzos Roussos #:

the "AI" many use to "create" trading bots , it is not better than us ... yet


I know what chatGPT is, but I don't understand why you are talking about it in this topic ?
 
Alain Verleyen #:
I know what chatGPT is, but I don't understand why you are talking about it in this topic ?

Because the code was produced by chatGPT . there are some signs , for now . 

For instance the double on calculate , the OP asked it for pivot high and lows and it assumed it needed two separate calculations on 2 separate oncalculate functions . 

 
Lorentzos Roussos #:

Because the code was produced by chatGPT . there are some signs , for now . 

For instance the double on calculate , the OP asked it for pivot high and lows and it assumed it needed two separate calculations on 2 separate oncalculate functions . 

Got it. Thanks.
Reason: