XY'de çizilen nesneler nasıl pürüzsüz hale getirilir (MT4 - MT5)

 

MT5 terminalindeki sorunu çözmeye yardımcı olun.

Ürünümü mql4'ten mql5'e aktarmaya karar verdim.

XY koordinatlarında çizilen dikdörtgenleri kullanır.

Ve MT4'te dikey ölçeği değiştirirken her şey pürüzsüz ve sarsıntısızsa, MT5'te aynı yaklaşım frizler ve gözle görülür bir "pürüzsüzlük" verir.

Etkisini göstermek için özel olarak basitleştirilmiş bir prototip yaptım. MT4 ve MT5 için aynı. Dikey ölçeği değiştirirken farkı karşılaştırın (fiyat ölçeğinde fare)


MT5'te her şey frensiz olacak, ancak yeniden çizim sarsıntılı olacak. Ve daha fazla nesne, daha kötü. Ve MT4 pürüzsüz.

mq4 ve mq5 kaynaklarını dosya olarak ekliyorum ve mq5 kodunu ekliyorum.


Pürüzsüz olmasına yardımcı olun.


Şunu anlamak istiyorum: "Bu" MT5 veya "Bu," MT5 kodum.


 //+------------------------------------------------------------------+
//|                                                  PrototypeXY.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link        " https://www.mql5.com "
#property version    "1.00"
#property indicator_chart_window

#property indicator_buffers 0
#property indicator_plots    0


string obj_name = "Asd_" ;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit (){

return ( INIT_SUCCEEDED );}

//+------------------------------------------------------------------+
//| 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[]){
   if (NewBar()){
      DrawObj();
   }
return (rates_total);}

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent ( const int id,
                   const long &lparam,
                   const double &dparam,
                   const string &sparam){
   if (id == CHARTEVENT_CHART_CHANGE ){
      DrawObj();
   }
}

//+------------------------------------------------------------------+
//| Выводим на график                                                |
//+------------------------------------------------------------------+

void DrawObj(){
   string GenName = obj_name;
   double startPricePos = SymbolInfoDouble ( Symbol (), SYMBOL_BID );
   int step_Pips = 50 ;
   for ( int i= 1 ; i<= 20 ;i++){
       double stp = (step_Pips*i)* SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
      RectLabelCreate(GenName+ "UP_" + IntegerToString (i),startPricePos + stp);
      RectLabelCreate(GenName+ "DN_" + IntegerToString (i),startPricePos - stp);
   }
   ChartRedraw ( 0 );
}

//+------------------------------------------------------------------+ 
//| Создает прямоугольную метку                                      | 
//+------------------------------------------------------------------+ 

void RectLabelCreate( string name,   // имя метки 
                     double price   // цена
                     ){
   const long              chart_ID= 0 ;               // ID графика
         int               sub_window= 0 ;             // номер подокна
         int               x= 0 ;                       // координата по оси X 
         int               y= 0 ;                       // координата по оси Y
         
   datetime time_pos_X_centr = 0 ; // Время по центру графика
   double price_pos_Y_tmp = 0 ;
   x=( int )( ChartGetInteger (chart_ID, CHART_WIDTH_IN_PIXELS ,sub_window)/ 2 );
   ChartXYToTimePrice (chart_ID,x,y,sub_window,time_pos_X_centr,price_pos_Y_tmp);         
         
   ChartTimePriceToXY (chart_ID,sub_window,time_pos_X_centr,price,x,y);

   const int               width= 50 ;                 // ширина 
   const int               height= 10 ;                 // высота 
   const color             back_clr= C'236,233,216' ;   // цвет фона 
   const ENUM_BORDER_TYPE border= BORDER_SUNKEN ;     // тип границы 
   const ENUM_BASE_CORNER corner= CORNER_LEFT_UPPER ; // угол графика для привязки 
   const color             clr= clrRed ;               // цвет плоской границы (Flat) 
   const ENUM_LINE_STYLE   style= STYLE_SOLID ;         // стиль плоской границы 
   const int               line_width= 1 ;             // толщина плоской границы 
   const bool              back= false ;               // на заднем плане 
   const bool              selection= false ;           // выделить для перемещений 
   const bool              hidden= true ;               // скрыт в списке объектов 
   const long              z_order= 0 ;                 // приоритет на нажатие мышью 

   if (!ObjectIsExist(name)){
       if ( ObjectCreate (chart_ID,name, OBJ_RECTANGLE_LABEL ,sub_window, 0 , 0 )){
         ObjectSetInteger (chart_ID,name, OBJPROP_XDISTANCE ,x); 
         ObjectSetInteger (chart_ID,name, OBJPROP_YDISTANCE ,y); 
         ObjectSetInteger (chart_ID,name, OBJPROP_XSIZE ,width); 
         ObjectSetInteger (chart_ID,name, OBJPROP_YSIZE ,height); 
         ObjectSetInteger (chart_ID,name, OBJPROP_BGCOLOR ,back_clr); 
         ObjectSetInteger (chart_ID,name, OBJPROP_BORDER_TYPE ,border); 
         ObjectSetInteger (chart_ID,name, OBJPROP_CORNER ,corner); 
         ObjectSetInteger (chart_ID,name, OBJPROP_COLOR ,clr); 
         ObjectSetInteger (chart_ID,name, OBJPROP_STYLE ,style); 
         ObjectSetInteger (chart_ID,name, OBJPROP_WIDTH ,line_width); 
         ObjectSetInteger (chart_ID,name, OBJPROP_BACK ,back); 
         ObjectSetInteger (chart_ID,name, OBJPROP_SELECTABLE ,selection); 
         ObjectSetInteger (chart_ID,name, OBJPROP_SELECTED ,selection); 
         ObjectSetInteger (chart_ID,name, OBJPROP_HIDDEN ,hidden); 
         ObjectSetInteger (chart_ID,name, OBJPROP_ZORDER ,z_order);
      }
   } else {
       ObjectSetInteger (chart_ID,name, OBJPROP_XDISTANCE ,x); 
       ObjectSetInteger (chart_ID,name, OBJPROP_YDISTANCE ,y); 
       ObjectSetInteger (chart_ID,name, OBJPROP_XSIZE ,width); 
       ObjectSetInteger (chart_ID,name, OBJPROP_YSIZE ,height);
       ObjectSetInteger (chart_ID,name, OBJPROP_BGCOLOR ,back_clr);
       ObjectSetInteger (chart_ID,name, OBJPROP_COLOR ,clr);   
   }
} 


//+------------------------------------------------------------------+
//| Есть-ли обьект на графике                                        |
//+------------------------------------------------------------------+

bool ObjectIsExist( string name){
   if ( ObjectGetString ( 0 ,name, OBJPROP_NAME , 0 )==name) return ( true );
return ( false );}

//+------------------------------------------------------------------+
//| Появился новый бар                                               |
//+------------------------------------------------------------------+

bool NewBar(){
   static int countLastBar= 0 ;
   int curBars = iBars ( Symbol (), PERIOD_CURRENT );
   bool flg = false ;
   if (countLastBar!=curBars){
      countLastBar=curBars;
      flg= true ;
   }
return (flg);}
Dosyalar:
 
Vitaliy Kuznetsov :

MT5 terminalindeki sorunu çözmeye yardımcı olun.

Ürünümü mql4'ten mql5'e aktarmaya karar verdim.

XY koordinatlarında çizilen dikdörtgenleri kullanır.

Ve MT4'te dikey ölçeği değiştirirken, her şey pürüzsüz ve sarsıntısızsa, MT5'te aynı yaklaşım frizler ve gözle görülür "pürüzsüzlük" verir.

Etkisini göstermek için özel olarak basitleştirilmiş bir prototip yaptım. MT4 ve MT5 için aynı. Dikey ölçeği değiştirirken farkı karşılaştırın (fiyat ölçeğinde fare)


MT5'te her şey frensiz olacak, ancak yeniden çizim sarsıntılı olacak. Ve daha fazla nesne, daha kötü. Ve MT4 pürüzsüz.

mq4 ve mq5 kaynaklarını dosya olarak ekliyorum ve mq5 kodunu ekliyorum.


Pürüzsüz olmasına yardımcı olun.


Şunu anlamak istiyorum: "Bu" MT5 veya "Bu," MT5 kodum.


Bu kodu henüz keşfetmedim veya çalıştırmadım, çünkü bilgisayarda değil, ancak gözünüze çarpan ilk şey, ChartXYToTimePrice ve ChartTimePriceToXY adlı iki eşzamansız işlevdir.
Gerçekçi olmayacak kadar yavaşlar. Bu konuda uzun süredir MQ ile kavga ediyorum, ama tamamen görmezden gelin.
Bu işlevlerin her birinin ~ 16 milisaniye yürütüldüğünü, yani 30'luk bir döngü ile yalnızca bu işlevlerin yürütülme süresinin 30 * 2 * 16 = ~ 1 sn olduğunu hatırlıyorum.
Herhangi bir pürüzsüzlükten söz edilmiyor.
Önce bu işlevleri döngüden çıkarmaya çalışın, sonra 30 kat daha hızlı çalışacaktır. iCanvas'ta uyguladım.
 
Profiler'da kontrol edin.
 
evet, yürütülmesi zamanın %99,76'sını alan 4 eşzamansız işlevle karşılaştınız.
Grafik özellikleri tablosu zaten mevcut olduğu için bu fonksiyonların asenkron olmaması gerektiğini uzun yıllardır MQ'ya kanıtlamaya çalışıyorum ve sadece bu özellikleri almak yeterli ve asenkron bir işleme başlamanın bir anlamı yok.
Ancak tüm çabalar boşunadır.
Gerçekten delilik kokuyor.
Tuval ve olay modelinin aktif kullanımı dahil olmak üzere birçok dilde programladığım için neden bahsettiğimi biliyorum.
Ayrıca, tarih öncesi MQL4'te bu sorun asgari düzeydedir.

 
Belki bu bir hata değil, bir özelliktir? Oradaki her şey grafiklerle optimize edilmiştir. Ve iyi çalışmıyor, çünkü her şeyi amaçlanan amaçları için kullanmak arzu edilir. Fiyat koordinatlarına bağlı özel grafik nesneler var - bu görev için kullanmanız gereken şey bu.
 
Nikolai Semko :
evet, yürütülmesi zamanın %99,76'sını alan 4 eşzamansız işlevle karşılaştınız.
...
Ayrıca, tarih öncesi MQL4'te bu sorun asgari düzeydedir.

Evet, her şey MT4'te uçuyor.

Nikolay Semko :
Önce bu işlevleri döngüden çıkarmaya çalışın, sonra 30 kat daha hızlı çalışacaktır. Bunu iCanvas'ta uyguladım.

Zorlaştırmıyorsa daha yetkin bir şekilde nasıl yapılacağına dair bir örnek verebilir misiniz?

 
Vitaliy Kuznetsov :

Evet, her şey MT4'te uçuyor.

Zorlaştırmıyorsa daha yetkin bir şekilde nasıl yapılacağına dair bir örnek verebilir misiniz?

En kısa yol, bir döngüde eşzamansız işlevleri kullanmama izin verecek olan iCanvas İncilimi eklemektir.
Bu durumda, tuvalin kendisini kullanmak hiç gerekli değildir. Bütün için grafiğinizde asılı kalacak, ancak boş ve şeffaf olacaktır.
iCanvas'ı kullanmadan daha uzun bir yöntem varsa, bu yöntemi bu İncil'de tekrar gözden geçirmeniz gerekecek, çünkü orada ve uygulanıyor, ancak bu aktivite kalbin zayıflığı için değil. :))
iCanvas'ın ne yaptığını kısaca açıklamaya çalışacağım.
CHARTEVENT_CHART_CHANGE olayını yakalayan ve dahili W yapısını aynı asenkron ChartGet işlevlerini kullanarak dolduran dahili bir OnChartEvent işleyicisine sahiptir, ancak bunu bu olayın gerçekleşmesiyle yalnızca bir kez yapar.
Bu, hızı aşağı yukarı optimize etmenize olanak tanır.
Ayrıca bu kitaplıkta, tam ekrana uzanan ve ekran değiştiğinde ona göre ayarlanan bir Canvas nesnesi asılıdır.


Burada, örneğin, üç satır kod eklenir ve birçok satır atılır:


 #property indicator_chart_window
#include <Canvas\iCanvas.mqh> // https://www.mql5.com/ru/code/22164

#property indicator_buffers 0
#property indicator_plots    0


string obj_name = "Asd_" ;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit () {
   return ( INIT_SUCCEEDED );
}
//+------------------------------------------------------------------+
//| 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[]) {
   if (NewBar()) {
      DrawObj();
   }
   return (rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent ( const int id,
                   const long &lparam,
                   const double &dparam,
                   const string &sparam) {
   if (id == CHARTEVENT_CHART_CHANGE ) {
      DrawObj();
   }
}
//+------------------------------------------------------------------+
//| Выводим на график                                                |
//+------------------------------------------------------------------+
void DrawObj() {
   string GenName = obj_name;
   double startPricePos = SymbolInfoDouble ( Symbol (), SYMBOL_BID );
   int step_Pips = 50 ;
   for ( int i= 1 ; i<= 20 ; i++) {
       double stp = (step_Pips*i)* SymbolInfoDouble ( Symbol (), SYMBOL_POINT );
      RectLabelCreate(GenName+ "UP_" + IntegerToString (i),startPricePos + stp);
      RectLabelCreate(GenName+ "DN_" + IntegerToString (i),startPricePos - stp);
   }
   ChartRedraw ( 0 );
}
//+------------------------------------------------------------------+
//| Создает прямоугольную метку                                      |
//+------------------------------------------------------------------+
void RectLabelCreate( string name,   // имя метки
                     double price   // цена
                    ) {
   const long   chart_ID= 0 ;               // ID графика
   int          sub_window= 0 ;             // номер подокна
   int          x= 0 ;                       // координата по оси X
   int          y= 0 ;                       // координата по оси Y
   x=W.Width/ 2 ;
   y = Round(Canvas.Y(price));
   //x=(int)(ChartGetInteger(chart_ID,CHART_WIDTH_IN_PIXELS,sub_window)/2);
   //ChartXYToTimePrice(chart_ID,x,y,sub_window,time_pos_X_centr,price_pos_Y_tmp);
   //ChartTimePriceToXY(chart_ID,sub_window,time_pos_X_centr,price,x,y);
   const int               width= 50 ;                 // ширина
   const int               height= 10 ;                 // высота
   const color             back_clr= C'236,233,216' ;   // цвет фона
   const ENUM_BORDER_TYPE border= BORDER_SUNKEN ;     // тип границы
   const ENUM_BASE_CORNER corner= CORNER_LEFT_UPPER ; // угол графика для привязки
   const color             clr= clrRed ;               // цвет плоской границы (Flat)
   const ENUM_LINE_STYLE   style= STYLE_SOLID ;         // стиль плоской границы
   const int               line_width= 1 ;             // толщина плоской границы
   const bool              back= false ;               // на заднем плане
   const bool              selection= false ;           // выделить для перемещений
   const bool              hidden= true ;               // скрыт в списке объектов
   const long              z_order= 0 ;                 // приоритет на нажатие мышью
   if ( ObjectCreate (chart_ID,name, OBJ_RECTANGLE_LABEL ,sub_window, 0 , 0 )) {
       ObjectSetInteger (chart_ID,name, OBJPROP_XDISTANCE ,x);
       ObjectSetInteger (chart_ID,name, OBJPROP_YDISTANCE ,y);
       ObjectSetInteger (chart_ID,name, OBJPROP_XSIZE ,width);
       ObjectSetInteger (chart_ID,name, OBJPROP_YSIZE ,height);
       ObjectSetInteger (chart_ID,name, OBJPROP_BGCOLOR ,back_clr);
       ObjectSetInteger (chart_ID,name, OBJPROP_BORDER_TYPE ,border);
       ObjectSetInteger (chart_ID,name, OBJPROP_CORNER ,corner);
       ObjectSetInteger (chart_ID,name, OBJPROP_COLOR ,clr);
       ObjectSetInteger (chart_ID,name, OBJPROP_STYLE ,style);
       ObjectSetInteger (chart_ID,name, OBJPROP_WIDTH ,line_width);
       ObjectSetInteger (chart_ID,name, OBJPROP_BACK ,back);
       ObjectSetInteger (chart_ID,name, OBJPROP_SELECTABLE ,selection);
       ObjectSetInteger (chart_ID,name, OBJPROP_SELECTED ,selection);
       ObjectSetInteger (chart_ID,name, OBJPROP_HIDDEN ,hidden);
       ObjectSetInteger (chart_ID,name, OBJPROP_ZORDER ,z_order);
   } else Print ( _LastError );
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool NewBar() {
   static int countLastBar= 0 ;
   int curBars = iBars ( Symbol (), PERIOD_CURRENT );
   bool flg = false ;
   if (countLastBar!=curBars) {
      countLastBar=curBars;
      flg= true ;
   }
   return (flg);
}
//+------------------------------------------------------------------+
Her durumda, bu algoritma ile nesne sayısını artırabilirsiniz ve bu, performansı büyük ölçüde etkilemeyecektir.
Dosyalar:
iCanvas.mqh  52 kb
 
Dmitry Fedoseev :
Belki bu bir hata değil, bir özelliktir? Oradaki her şey grafiklerle optimize edilmiştir. Ve iyi çalışmıyor, çünkü her şeyi amaçlanan amaçları için kullanmak arzu edilir. Fiyat koordinatlarına bağlı özel grafik nesneler var - bu görev için kullanmanız gereken şey bu.

Ben de günahkar bir amelden önce, bu hususta ilim eklenene kadar öyle sanıyordum.
Nedeni açık - düşüncesizlik.
En başta (10 yıl önce) bir tür "otorite" batırdı ve hala batırabileceği kimsenin aklına gelmiyor.
https://www.mql5.com/ru/forum/1111/page2780#comment_16886162
Görünüşe göre bir şekilde anlaştılar ve sonuçlandırmak için söz verdiler, ama hayır - gol attılar. Woz ve şimdi orada.
https://www.mql5.com/ru/forum/1111/page2781#comment_16904132


 
Nikolai Semko :

En kısa yol, bir döngüde eşzamansız işlevleri kullanmama izin verecek olan iCanvas İncilimi eklemektir.
Bu durumda, tuvalin kendisini kullanmak hiç gerekli değildir. Bütün için grafiğinizde asılı kalacak, ancak boş ve şeffaf olacaktır.
iCanvas'ı kullanmadan daha uzun bir yöntem varsa, bu yöntemi bu İncil'de tekrar gözden geçirmeniz gerekecek, çünkü orada ve uygulanıyor, ancak bu aktivite kalbin zayıflığı için değil. :))
iCanvas'ın ne yaptığını kısaca açıklamaya çalışacağım.
CHARTEVENT_CHART_CHANGE olayını yakalayan ve dahili W yapısını aynı asenkron ChartGet işlevlerini kullanarak dolduran dahili bir OnChartEvent işleyicisine sahiptir, ancak bunu bu olayın gerçekleşmesiyle yalnızca bir kez yapar.
Bu, hızı aşağı yukarı optimize etmenize olanak tanır.
Ayrıca bu kitaplıkta, tam ekrana uzanan ve ekran değiştiğinde ona göre ayarlanan bir Canvas nesnesi asılıdır.


Burada, örneğin, üç satır kod eklenir ve birçok satır atılır:

Her durumda, bu algoritma ile nesne sayısını artırabilirsiniz ve bu, performansı büyük ölçüde etkilemeyecektir.

Böyle bir çözüm için teşekkür ederiz. Gerçekten de, oluşturma hızı arttı. Görünüşe göre kütüphaneyi öğrenmem gerekecek.

Aşağıdaki nüansı açıklığa kavuşturmak istiyorum. Bu formülasyon bir uyarı ile derlenir:

y = Canvas.Y(price);

Ve bununla uyarı olmadan, ancak hız biraz düşüyor

y = ( int )Canvas.Y(price);

Hangisi daha iyi?)

 
Vitaliy Kuznetsov :

Sorunu bu şekilde çözdüğünüz için teşekkürler. Gerçekten de, oluşturma hızı arttı. Görünüşe göre kütüphaneyi öğrenmem gerekecek.

Aşağıdaki nüansı açıklığa kavuşturmak istiyorum. Bu formülasyon bir uyarı ile derlenir:

Ve bununla uyarı olmadan, ancak hız biraz düşüyor

Hangisi daha iyi?)

ne tür bir "y"ye sahipsin?

çünkü int ve nesnel olarak "hız biraz düştü" ise bu bir HATA

 
Ne tür bir Canvas.Y(fiyat);

ne tür döner
Neden: