Análogo a iBarShift - página 16

 

En general, leí en diagonal y sólo las primeras páginas (tal vez en el medio era la cabeza brillante de alguien? :) ), algo que todos tratan de añadir muletas a la interfaz de terminal terriblemente incómodo para acceder a la historia, es más fácil escribir una almohadilla entre el terminal y sus propias cosas (en general, debe estar en la biblioteca std). Además, como resultado, usted no tiene que escribir diferentes scripts para 4/5. Yo he hecho algo así:

// 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;
}

Y un ejemplo de uso sencillo:

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

refresh() a través de define su propia para 4/5. El gráfico tiene sólo un período (M1 u otro definido a través de definir, ¿por qué esta molestia con su abundancia?)

También he implementado algunas características útiles - indexación reverse_mode() desde cualquier lado (si es de izquierda a derecha, los índices siguen siendo válidos al desplegar el gráfico). Capacidad de establecer y mover el borde del gráfico set_curtainpos(), análogo al probador - probar, mover el límite, probar, mover. Operadores de comparación sobrecargados en la estructura Mi_punto (para un comportamiento válido en tales situaciones: 0,0000000009 == 1,0000000000).

Si alguien agoniza, recomiendo este enfoque, personalmente no me arrepiento.

Zy: y renuncié a los clásicos candelabros con open/close/high/low, y puse Point en base - un candelabro da dos Point's bearish high->low, bullish low-high. es realmente muy conveniente.

 
Aleksey Vyazmikin:

Esperaré las correcciones en la forma final, gracias por responder.

¡Buena suerte con los exámenes!

Resultó ser muy matizado.

Si hubiera sabido lo complicado que sería, no me habría involucrado ))))

Esta opción debería funcionar correctamente.
Si alguien encuentra que funciona mal, le agradecería que informara del problema.


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));}
//+------------------------------------------------------------------+
 
¿En qué se diferencia su iBars() en cuanto a rendimiento del Bars() estándar?
 
Artyom Trishkin:
¿En qué medida difiere su iBars() en cuanto a rendimiento del Bars() estándar?

Depende de cómo lo uses.
Si cada llamada al iBar cambia el TF o el símbolo, entonces mi iBar será aproximadamente la mitad de lento.

Pero esta situación no es en absoluto realista desde un punto de vista práctico.

Si lo usas así, por ejemplo:

entonces la ventaja de mis iBars sobre las barras normales será de unas 10 veces o más.

Pero lo más importante es que no hay ningún error de colgado:

   Print("1");
   Print(Bars(_Symbol,PERIOD_D1,D'2018.05.02 01:58:03',D'2018.05.02 12:56:11')); // вычисляется более 10 секунд !!!!
   Print("2");
Archivos adjuntos:
 
Había un error que ocurría si se pasaba 0 =PERIOD_CURRENT como TF
Lo he corregido en el código anterior. Se ha añadido una línea:
if (timeframe==0) timeframe=_Period;
 
Nikolai Semko:

Depende de cómo lo uses.
Si cada llamada a iBar cambia el TF o el símbolo, entonces mi iBar funcionará el doble de lento.

Pero esta es una situación completamente irreal desde un punto de vista práctico.

Si lo usas así, por ejemplo:

entonces la ventaja de mis iBars sobre las Barras estándar sería unas 10 veces o más.

Pero lo más importante es que no hay ningún error de colgado:

¡R-R-R-R-RESPETO!

 
Nikolai Semko:

Depende de cómo lo uses.
Si cada llamada a iBar cambia el TF o el símbolo, entonces mi iBar funcionará unas dos veces más lento.

Pero esta situación no es en absoluto realista desde un punto de vista práctico.

Si lo usas así, por ejemplo:

entonces la ventaja de mis iBars sobre las Barras estándar sería unas 10 veces o más.

Pero lo principal es que no hay ningún fallo de congelación:

¡Vamos!

¿Dónde están tus 10 segundos?

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:

¡Vamos!

¿Dónde están tus 10 segundos?

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

¿Era MT5?
En MT4 este error no existe.
 
Nikolai Semko:
¿Era MT5?
Este error no está presente en MT4.
MT4
 
Renat Akhtyamov:
MT4

Pruébalo en MT5 y sorpréndete.

Este error fue descubierto completamente por accidente gracias al post de @Aleksey Vyazmikin, por lo que tengo que agradecerle mucho.

Ya había observado estas interrupciones, pero no podía explicar su origen. Quién iba a pensar...

Razón de la queja: