Analogue à iBarShift - page 16

 

En général, je lis en diagonale et seulement les premières pages (peut-être qu'au milieu il y avait la tête brillante de quelqu'un ? :) ), tout le monde essaie d'ajouter des béquilles à l'interface terriblement incommode du terminal pour accéder à l'historique, il est plus facile d'écrire une couche entre le terminal et leur propre truc (en général, il devrait être dans la bibliothèque std). En outre, en conséquence, vous n'avez pas besoin d'écrire des scripts différents pour 4/5. J'ai fait une telle chose :

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

Et un exemple d'utilisation simple :

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

refresh() via définit le sien pour 4/5. Le graphique n'a qu'une seule période (M1 ou autre définie via define, pourquoi ce tracas avec leur abondance ?).

J'ai également implémenté quelques fonctionnalités utiles - reverse_mode() indexation de n'importe quel côté (si de gauche à droite, les index restent valides lors du dépliage du graphique). Possibilité de définir et de déplacer le bord du graphique set_curtainpos(), analogue du testeur - test, déplacement de la limite, test, déplacement. Opérateurs de comparaison surchargés à la structure My_point (pour un comportement valide dans de telles situations : 0.0000000009 == 1.0000000000).

Si quelqu'un agonise, je recommande cette approche, personnellement je ne suis pas désolé.

Zy : et j'ai abandonné les chandeliers classiques avec ouverture/fermeture/haut/bas, et j'ai mis le Point dans les bases - un chandelier donne deux Point's baissier haut>bas, haussier bas-haut. c'est vraiment très pratique.

 
Aleksey Vyazmikin:

J'attendrai les corrections dans la forme finale, merci de m'avoir répondu.

Bonne chance pour les examens !

Il s'est avéré être très nuancé.

Si j'avais su à quel point c'était compliqué, je ne me serais pas engagé )))).

Cette option devrait fonctionner correctement.
Si quelqu'un constate que le système ne fonctionne pas correctement, je lui serais reconnaissant de signaler le problème.


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));}
//+------------------------------------------------------------------+
 
Comment votre iBars() diffère-t-elle en termes de performance de la Bars() standard ?
 
Artyom Trishkin:
Dans quelle mesure les performances de votre iBars() diffèrent-elles de celles de la fonction standard Bars() ?

Cela dépend de la façon dont vous l'utilisez.
Si chaque appel à l'iBar change le TF ou le symbole, alors mon iBar sera environ deux fois moins lent.

Mais ce n'est absolument pas une situation réaliste d'un point de vue pratique.

Si vous l'utilisez comme ça, par exemple :

alors l'avantage de mes iBars par rapport aux barres ordinaires sera environ 10 fois ou plus.

Mais l'essentiel est qu'il n'y a pas de bug de raccrochage :

   Print("1");
   Print(Bars(_Symbol,PERIOD_D1,D'2018.05.02 01:58:03',D'2018.05.02 12:56:11')); // вычисляется более 10 секунд !!!!
   Print("2");
Dossiers :
 
Une erreur se produisait si 0 =PERIOD_CURRENT était passé comme TF
Je l'ai corrigé dans le code ci-dessus. Ajouté une ligne :
if (timeframe==0) timeframe=_Period;
 
Nikolai Semko:

Cela dépend de la façon dont vous l'utilisez.
Si chaque appel à l'iBar change le TF ou le symbole, alors mon iBar fonctionnera environ deux fois plus lentement.

Mais cette situation est totalement irréaliste d'un point de vue pratique.

Si vous l'utilisez comme ça, par exemple :

alors l'avantage de mes iBars par rapport aux barres standard serait d'environ 10 fois ou plus.

Mais l'essentiel est qu'il n'y a pas de bug de raccrochage :

R-R-R-R-RESPECT !

 
Nikolai Semko:

Cela dépend de la façon dont vous l'utilisez.
Si chaque appel à l'iBar change le TF ou le symbole, alors mon iBar fonctionnera environ deux fois plus lentement.

Mais ce n'est absolument pas une situation réaliste d'un point de vue pratique.

Si vous l'utilisez comme ça, par exemple :

alors l'avantage de mes iBars par rapport aux barres standard serait environ 10 fois ou plus.

Mais l'essentiel est qu'il n'y a pas de bug de congélation :

Allez !

Où sont vos 10 secondes ?

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:

Allez !

Où sont vos 10 secondes ?

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

C'était MT5 ?
Sur MT4, ce bug n'existe pas.
 
Nikolai Semko:
C'était MT5 ?
Ce bug n'est pas présent sur MT4.
MT4
 
Renat Akhtyamov:
MT4

Essayez-le sur MT5 et soyez surpris.

Ce bug a été découvert complètement par accident grâce au post de @Aleksey Vyazmikin, pour lequel je dois le remercier beaucoup.

J'avais déjà observé ces interruptions auparavant, mais je ne pouvais pas expliquer leur origine. Qui aurait pu penser...