Analogo a iBarShift - pagina 16

 

In generale, leggo in diagonale e solo le prime pagine (forse nel mezzo c'era la testa luminosa di qualcuno? :) ), tutti stanno cercando di aggiungere stampelle all'interfaccia terminale terribilmente scomoda per accedere alla storia, è più facile scrivere un livello tra il terminale e le proprie cose (in generale, dovrebbe essere in libreria std). Inoltre, come risultato, non è necessario scrivere script diversi per 4/5. Ho fatto una cosa del genere:

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

E un semplice esempio di utilizzo:

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

refresh() via definisce il proprio per 4/5. Il grafico ha un solo periodo (M1 o altro impostato tramite define, perché questo fastidio con la loro abbondanza?)

Inoltre ho implementato alcune caratteristiche utili - reverse_mode() indicizzazione da entrambi i lati (se da sinistra a destra, gli indici rimangono validi quando si dispiega il grafico). Possibilità di impostare e spostare il bordo del grafico set_curtainpos(), analogo del tester - prova, sposta confine, prova, sposta. Operatori di confronto sovraccaricati nella struttura My_point (per un comportamento valido in tali situazioni: 0,0000000009 == 1,0000000000).

Se qualcuno agonizza, consiglio questo approccio, personalmente non mi dispiace.

Zy: e ho rinunciato alle candele classiche con open/close/high/low, e ho messo Point nelle basi - una candela dà due Point's bearish high->low, bullish low-high. questo è davvero molto utile.

 
Aleksey Vyazmikin:

Aspetterò le correzioni nella forma finale, grazie per aver risposto.

Buona fortuna per gli esami!

Si è rivelato essere molto sfumato.

Se avessi saputo quanto sarebbe stato complicato, non mi sarei fatto coinvolgere ))))

Questa opzione dovrebbe funzionare correttamente.
Se qualcuno lo trova funzionante in modo scorretto, sarei grato se potesse segnalare il 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));}
//+------------------------------------------------------------------+
 
In che modo la vostra iBars() differisce in termini di prestazioni dalla Bars() standard?
 
Artyom Trishkin:
Quanto la vostra iBars() differisce in termini di prestazioni dalla Bars() standard?

Dipende da come lo si usa.
Se ogni chiamata alla iBar cambia il TF o il simbolo, allora la mia iBar sarà circa la metà più lenta.

Ma questa non è assolutamente una situazione realistica da un punto di vista pratico.

Se lo usi così, per esempio:

allora il vantaggio delle mie iBar rispetto alle Barre normali sarà circa 10 volte o più.

Ma la cosa principale è che non c'è nessun bug di blocco:

   Print("1");
   Print(Bars(_Symbol,PERIOD_D1,D'2018.05.02 01:58:03',D'2018.05.02 12:56:11')); // вычисляется более 10 секунд !!!!
   Print("2");
File:
 
C'era un errore che si verificava se 0 =PERIOD_CURRENT veniva passato come TF
L'ho corretto nel codice sopra. Aggiunta una linea:
if (timeframe==0) timeframe=_Period;
 
Nikolai Semko:

Dipende da come lo si usa.
Se ogni chiamata a iBar cambierà TF o simbolo, allora la mia iBar lavorerà circa due volte più lentamente.

Ma questa è una situazione completamente irrealistica da un punto di vista pratico.

Se lo usi così, per esempio:

allora il vantaggio delle mie iBars rispetto alle Bars standard sarebbe circa 10 volte o più.

Ma la cosa principale è che non c'è nessun bug di blocco:

R-R-R-R-RISPETTO!

 
Nikolai Semko:

Dipende da come lo si usa.
Se ogni chiamata a iBar cambierà TF o simbolo, allora la mia iBar lavorerà circa due volte più lentamente.

Ma questa non è assolutamente una situazione realistica da un punto di vista pratico.

Se lo usi così, per esempio:

allora il vantaggio delle mie iBars rispetto alle Bars standard sarebbe circa 10 volte o più.

Ma la cosa principale è che non c'è nessun bug di congelamento:

Forza!

Dove sono i tuoi 10 secondi?

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:

Forza!

Dove sono i tuoi 10 secondi?

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?
Su MT4 questo bug non c'è.
 
Nikolai Semko:
Era MT5?
Questo bug non è presente su MT4.
MT4
 
Renat Akhtyamov:
MT4

Provatelo su MT5 e rimanete sorpresi.

Questo bug è stato scoperto completamente per caso grazie al post di @Aleksey Vyazmikin, per il quale devo ringraziarlo molto.

Avevo già osservato queste interruzioni, ma non riuscivo a spiegarne l'origine. Chi l'avrebbe mai detto...

Motivazione: