Analogue to iBarShift - page 16

 

In general, I read diagonally and only first pages (maybe in the middle there was someone's bright head? :) ), everyone is trying to add crutches to terribly inconvenient terminal interface to access the history, it's easier to write a layer between the terminal and their own stuff (in general, it should be in std library). In addition, as a result, you do not need to write different scripts for 4/5. I have done such a thing:

// comp.comp() returns true if the first argument is less than the second.
// If failure, returns UINT_MAX.
template<typename A, typename T, typename Comp>
uint alg_lower_bound(const A &ar[], uint minindex, uint maxindex,
                     const T &value, Comp &comp, bool rev=false)
{
   uint count = maxindex - minindex + 1;
   uint first = minindex;
   if(rev)
      first = maxindex;
      
   while(count != 0)
   {
      uint it = first;
      uint step = count / 2;
      if(rev)
         it -= step;
      else
         it += step;
      if(comp.comp(ar[it], value))
      {
         if(rev)
            first = --it;
         else
            first = ++it;
         count -= step + 1;
      }
      else
         count = step;
   }
   
   if(first < minindex  ||  first > maxindex)
      first = UINT_MAX;
   return first;
}

class Chart
{
   struct Bar_trend
   {
      double p1;
      double p2;
      datetime time;
   };
   Bar_trend bar_trend[];
   upindex_t sz;
   upindex_t curtain;
   bool reverse_f;
   void refresh_base(datetime min = 0, datetime max = 0);
public:
   // Empty chart will be created.
   Chart(): sz(0), curtain(UPINDEXT_MAX), reverse_f(false) {}
   // Chart with points whose time is in interval min:max will be created.
   Chart(datetime min, datetime max): sz(0), curtain(UPINDEXT_MAX), reverse_f(false) { refresh_base(min, max); }
   // Reverse flag is not changed. For whole chart min and max are 0.
   void init(datetime min, datetime max);
   My_point operator[](upindex_t i)const;
   // If exact is true then time of point with returned index is equal to time.
   // If point is not found then function returns UPINDEXT_MAX.
   upindex_t bar_shift(datetime time, bool exact=true)const;
   upindex_t size()const  {return this.curtain == UPINDEXT_MAX  ?  this.sz * 2  :  this.curtain;}
   // pos can not be greater than the size(). UPINDEXT_MAX for deletion of curtain.
   // It will be reset when refresh(). Returns true in case of success.
   bool set_curtainpos(upindex_t pos);
   upindex_t get_curtainpos()const  {return this.curtain;}
   bool reverse_mode()const  {return this.reverse_f;}
   // Returns true in case of success.
   bool reverse_mode(bool mode);
   // if chart size == 0 then lowest = highest == UPINDEXT_MAX.
   void extremums(upindex_t &lowest, upindex_t &highest)const;
   // if chart is reverse then indexes will be invalidated.
   void refresh()  { refresh_base(); }
};

upindex_t Chart::bar_shift(datetime time, bool exact)const
{
   class Comp
   {
   public:
      bool comp(const Bar_trend &bt, datetime time)  {return bt.time > time;}
   }comp;
   
   uint res = alg_lower_bound(this.bar_trend, 0, this.sz-1, time, comp, true);
   if(res != UINT_MAX)
   {
      uchar shift = this.bar_trend[res].time!=time ? 1 : 0;

      if(exact  &&  this.bar_trend[res].time+shift != time)
         res = UINT_MAX;
      else
         res = this.reverse_f ? 
               ((this.sz - 1 - res) * 2 + !shift) :  
               (res * 2 + shift);
   }
   return res == UINT_MAX ? UPINDEXT_MAX : res;
}

And a simple usage example:

Chart chart();
chart.refresh();
for(int i = 0;  i < chart.size();  ++i)
   Print(chart[i].price, chart[i].time);

refresh() via defines its own for 4/5. The chart has only one period (M1 or other set via define, why this hassle with their abundance?).

Also I have implemented some useful features - reverse_mode() indexing from either side (if left to right, the indexes remain valid when unfolding chart). Ability to set and move chart edge set_curtainpos(), analog of the tester - test, move boundary, test, move. Overloaded comparison operators at structure My_point (for valid behavior in such situations: 0.0000000009 == 1.0000000000).

If someone agonizes, I recommend this approach, personally I'm not sorry.

Zy: and i gave up classic candlesticks with open/close/high/low, and put Point in the basics - one candlestick gives two Point's bearish high->low, bullish low-high. this is really very handy.

 
Aleksey Vyazmikin:

I will wait for the corrections in the final form, thank you for replying.

Good luck with the exams!

It turned out to be very nuanced.

If I had known how complicated it would be, I wouldn't have got involved ))))

This option should work correctly.
If anyone finds it working incorrectly, I'd be grateful if they could report the problem.


int iBarShift(const string Symb,const ENUM_TIMEFRAMES TimeFrame,datetime time,bool exact=false)
  {
   int Res=iBars(Symb,TimeFrame,time+1,UINT_MAX);
   if(exact) if((TimeFrame!=PERIOD_MN1 || time>TimeCurrent()) && Res==iBars(Symb,TimeFrame,time-PeriodSeconds(TimeFrame)+1,UINT_MAX)) return(-1);
   return(Res);
  }
int iBars(string symbol_name,ENUM_TIMEFRAMES  timeframe,datetime start_time,datetime stop_time) // stop_time > start_time
  {
   static string LastSymb=NULL;
   static ENUM_TIMEFRAMES LastTimeFrame=0;
   static datetime LastTime=0;
   static datetime LastTime0=0;
   static int PerSec=0;
   static int PreBars=0,PreBarsS=0,PreBarsF=0;
   static datetime LastBAR=0;
   static datetime LastTimeCur=0;
   static bool flag=true;
   static int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS);
   datetime TimeCur;
   if (timeframe==0) timeframe=_Period;
   const bool changeTF=LastTimeFrame!=timeframe;
   const bool changeSymb=LastSymb!=symbol_name;
   const bool change=changeTF || changeSymb || flag;

   LastTimeFrame=timeframe; LastSymb=symbol_name;
   if(changeTF) PerSec=::PeriodSeconds(timeframe); if(PerSec==0) { flag=true; return(0);}

   if(stop_time<start_time)
     {
      TimeCur=stop_time;
      stop_time=start_time;
      start_time=TimeCur;
     }
   if(changeSymb)
     {
      if(!SymbolInfoInteger(symbol_name,SYMBOL_SELECT))
        {
         SymbolSelect(symbol_name,true);
         ChartRedraw();
        }
     }
   TimeCur=TimeCurrent();
   if(timeframe==PERIOD_W1) TimeCur-=(TimeCur+345600)%PerSec; // 01.01.1970 - Thursday. Minus 4 days.
   if(timeframe<PERIOD_W1) TimeCur-=TimeCur%PerSec;
   if(start_time>TimeCur) { flag=true; return(0);}
   if(timeframe==PERIOD_MN1)
     {
      MqlDateTime dt;
      TimeToStruct(TimeCur,dt);
      TimeCur=dt.year*12+dt.mon;
     }

   if(changeTF || changeSymb || TimeCur!=LastTimeCur)
      LastBAR=(datetime)SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE);

   LastTimeCur=TimeCur;
   if(start_time>LastBAR) { flag=true; return(0);}

   datetime tS,tF=0;
   if(timeframe==PERIOD_W1) tS=start_time-(start_time+345599)%PerSec-1;
   else if(timeframe<PERIOD_MN1) tS=start_time-(start_time-1)%PerSec-1;
   else  //  PERIOD_MN1
     {
      MqlDateTime dt;
      TimeToStruct(start_time-1,dt);
      tS=dt.year*12+dt.mon;
     }
   if(change || tS!=LastTime) { PreBarsS=Bars(symbol_name,timeframe,start_time,UINT_MAX); LastTime=tS;}
   if(stop_time<=LastBAR)
     {
      if(PreBarsS>=max_bars) PreBars=Bars(symbol_name,timeframe,start_time,stop_time);
      else
        {
         if(timeframe<PERIOD_W1) tF=stop_time-(stop_time)%PerSec;
         else if(timeframe==PERIOD_W1) tF=stop_time-(stop_time+345600)%PerSec;
         else //  PERIOD_MN1
           {
            MqlDateTime dt0;
            TimeToStruct(stop_time-1,dt0);
            tF=dt0.year*12+dt0.mon;
           }
         if(change || tF!=LastTime0)
           { PreBarsF=Bars(symbol_name,timeframe,stop_time+1,UINT_MAX); LastTime0=tF; }
         PreBars=PreBarsS-PreBarsF;
        }
     }
   else PreBars=PreBarsS;
   flag=false;
   return(PreBars);
  }
//+------------------------------------------------------------------+
int iBars(string symbol_name,ENUM_TIMEFRAMES  timeframe) {return(Bars(symbol_name,timeframe));}
//+------------------------------------------------------------------+
 
How does your iBars() differ in performance from the standard Bars() ?
 
Artyom Trishkin:
How much does your iBars() differ in performance from the standard Bars()?

It depends on how you use it.
If every call to the iBar changes the TF or symbol, then my iBar will be about half as slow.

But this is absolutely not a realistic situation from a practical point of view.

If you use it like this, for example:

then the advantage of my iBars over the regular Bars will be about 10 times or more.

But the main thing is that there is no hang-up bug:

   Print("1");
   Print(Bars(_Symbol,PERIOD_D1,D'2018.05.02 01:58:03',D'2018.05.02 12:56:11')); // вычисляется более 10 секунд !!!!
   Print("2");
Files:
 
There was an error that occurred if 0 =PERIOD_CURRENT was passed as TF
Fixed it in the code above. Added a line:
if (timeframe==0) timeframe=_Period;
 
Nikolai Semko:

It depends on how you use it.
If each call to iBar will change TF or symbol, then my iBar will work about twice as slow.

But this is absolutely not a realistic situation from a practical point of view.

If you use it like this, for example:

then the advantage of my iBars over the standard Bars would be about 10 times or more.

But the main thing is that there is no hang-up bug:

R-R-R-R-RESPECT!

 
Nikolai Semko:

It depends on how you use it.
If each call to iBar will change TF or symbol, then my iBar will work about twice as slow.

But this is absolutely not a realistic situation from a practical point of view.

If you use it like this, for example:

then the advantage of my iBars over the standard Bars would be about 10 times or more.

But the main thing is that there is no freezing bug:

Come on!

Where is your 10 seconds?

2018.05.05 17:45:36.860 ind EURUSD,M5: 2
2018.05.05 17:45:36.860 ind EURUSD,M5: 0
2018.05.05 17:45:36.860 ind EURUSD,M5: 1

 
Renat Akhtyamov:

Come on!

Where's your 10 seconds?

2018.05.05 17:45:36.860 ind EURUSD,M5: 2
2018.05.05 17:45:36.860 ind EURUSD,M5: 0
2018.05.05 17:45:36.860 ind EURUSD,M5: 1

Was it MT5?
On MT4 this bug is not there.
 
Nikolai Semko:
Was it MT5?
This bug is not present on MT4.
MT4
 
Renat Akhtyamov:
MT4

Try it on MT5 and be surprised.

This bug was discovered completely by accident thanks to@Aleksey Vyazmikin' s post, for which I have to thank him very much.

I had been observing these interruptions before, but could not explain their origin. Who would have thought...