XY로 그려진 물체를 매끄럽게 만드는 방법(MT4 vs MT5)

Vitaliy Kuznetsov  

MT5 터미널의 문제를 해결하는 데 도움을 주세요.

내 제품을 mql4에서 mql5로 이전하기로 결정했습니다.

XY 좌표로 그려진 사각형을 사용합니다.

그리고 MT4에서 수직 스케일을 변경할 때 모든 것이 부드럽고 저크가 없다면 MT5에서도 동일한 접근 방식이 프리즈와 눈에 띄는 "부드러움"을 제공합니다.

효과를 보여드리기 위해 특별히 단순화된 프로토타입을 만들었습니다. MT4와 MT5도 마찬가지입니다. 세로 눈금 변경 시 차이점 비교(가격 눈금에 마우스)


MT5에서는 모든 것이 브레이크 없이 작동하지만 다시 그리기가 느릴 것입니다. 그리고 개체가 많을수록 더 나빠집니다. 그리고 MT4는 부드럽습니다.

mq4 및 mq5 소스를 파일로 첨부하고 mq5 코드를 삽입합니다.


원활하게 도와주세요.


이해하고 싶습니다: "이것은" MT5 또는 "이것은" MT5에 대한 내 코드입니다.


 //+------------------------------------------------------------------+
//|                                                  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);}
파일:
Nikolai Semko  
Vitaliy Kuznetsov :

MT5 터미널의 문제를 해결하는 데 도움을 주세요.

내 제품을 mql4에서 mql5로 이전하기로 결정했습니다.

XY 좌표로 그려진 사각형을 사용합니다.

그리고 MT4에서 수직 스케일을 변경할 때 모든 것이 부드럽고 저크가 없다면 MT5에서도 동일한 접근 방식으로 프리즈와 눈에 띄는 "부드러움"이 생깁니다.

효과를 보여드리기 위해 특별히 단순화된 프로토타입을 만들었습니다. MT4와 MT5도 마찬가지입니다. 세로 눈금 변경 시 차이점 비교(가격 눈금에 마우스)


MT5에서는 모든 것이 브레이크 없이 작동하지만 다시 그리기가 느슨해집니다. 그리고 개체가 많을수록 더 나빠집니다. 그리고 MT4는 부드럽습니다.

mq4 및 mq5 소스를 파일로 첨부하고 mq5 코드를 삽입합니다.


원활하게 도와주세요.


이해하고 싶습니다: "이것은" MT5 또는 "이것은" MT5에 대한 내 코드입니다.


아직 이 코드를 탐색하거나 실행하지 않았습니다. 컴퓨터가 아니라 가장 먼저 눈에 띄는 것은 두 개의 비동기 함수 ChartXYToTimePrice 및 ChartTimePriceToXY입니다.
그들은 비현실적으로 느립니다. 나는 이 주제에 대해 오랫동안 MQ와 싸워왔지만 완전히 무시했습니다.
이 기능들 각각이 ~16밀리초, 즉 30주기로 실행되는 것을 기억합니다. 이 기능들만을 실행하는 시간은 30 * 2 * 16 = ~ 1초입니다.
부드러움에 대한 언급이 없습니다.
먼저 루프에서 이러한 기능을 제거하면 30배 더 빠르게 작동합니다. iCanvas에서 구현했습니다.
Nikolai Semko  
네, 4개의 비동기 함수를 만났습니다. 이 함수를 실행하는 데 걸리는 시간은 99.76%입니다.
차트 속성 테이블이 이미 존재하고 이러한 속성을 가져오는 것으로 충분하고 비동기식 프로세스를 시작할 의미가 없기 때문에 이러한 함수가 비동기식이어서는 안 된다는 것을 MQ에 수년 동안 증명하려고 했습니다.
그러나 모든 노력은 헛된 것입니다.
정말 미친 듯이 느껴집니다.
나는 캔버스와 이벤트 모델의 적극적인 사용을 포함하여 많은 언어로 프로그래밍하기 때문에 내가 무슨 말을 하는지 알고 있습니다.
또한 선사시대 MQL4에서는 이 문제가 최소화되었습니다.

Dmitry Fedoseev  
버그가 아니라 기능일까요? 모든 것이 그래픽으로 최적화되어 있습니다. 그리고 모든 것을 의도 된 목적으로 사용하는 것이 바람직하기 때문에 잘 작동하지 않습니다. 가격 좌표 에 연결된 특수 그래픽 개체가 있습니다. 이것이 이 작업에 사용해야 하는 것입니다.
Vitaliy Kuznetsov  
Nikolai Semko :
네, 4개의 비동기 함수를 만났습니다. 실행 시간은 99.76%입니다.
...
또한 선사시대 MQL4에서는 이 문제가 최소화되었습니다.

예, 모든 것이 MT4로 날아갑니다.

니콜라이 셈코 :
먼저 루프에서 이러한 기능을 제거하면 30배 더 빠르게 작동합니다. iCanvas에서 구현했습니다.

어렵지 않다면 어떻게 하면 좀 더 능숙하게 할 수 있는지 예시를 들어주실 수 있나요?

Nikolai Semko  
Vitaliy Kuznetsov :

예, 모든 것이 MT4로 날아갑니다.

어렵지 않다면 어떻게 하면 좀 더 능숙하게 할 수 있는지 예시를 들어주실 수 있나요?

가장 짧은 방법은 루프에서 비동기 기능을 사용하지 못하도록 하는 iCanvas 성경을 첨부하는 것입니다.
이 경우 캔버스 자체를 사용할 필요가 전혀 없습니다. 차트에 전체적으로 표시되지만 비어 있고 투명합니다.
iCanvas를 사용하지 않고 더 긴 방법이 있다면 이 방법을 이 성경에서 다시 살펴봐야 합니다. 그것은 거기에 있고 실행되지만 이 직업은 희미한 마음을 위한 것이 아닙니다. :))
iCanvas가 하는 일을 간단히 설명하겠습니다.
CHARTEVENT_CHART_CHANGE 이벤트를 포착하고 동일한 모든 비동기 ChartGet 함수를 사용하여 내부 W 구조를 채우는 내부 OnChartEvent 핸들러가 있지만 이 이벤트가 발생할 때 한 번만 수행합니다.
이를 통해 속도를 어느 정도 최적화할 수 있습니다.
또한 이 라이브러리에는 전체 화면으로 확장되고 화면이 변경될 때 조정되는 Canvas 개체가 있습니다.


예를 들어 다음과 같이 세 줄의 코드가 추가되고 많은 줄이 삭제됩니다.


 #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);
}
//+------------------------------------------------------------------+
어쨌든 이 알고리즘으로 개체 수를 늘릴 수 있으며 성능에 큰 영향을 미치지 않습니다.
파일:
iCanvas.mqh  52 kb
Nikolai Semko  
Dmitry Fedoseev :
버그가 아니라 기능일까요? 모든 것이 그래픽으로 최적화되어 있습니다. 그리고 모든 것을 의도 된 목적으로 사용하는 것이 바람직하기 때문에 잘 작동하지 않습니다. 가격 좌표 에 연결된 특수 그래픽 개체가 있습니다. 이것이 이 작업에 사용해야 하는 것입니다.

나는 또한 이 문제에 대한 지식이 추가되기 전까지는 죄를 짓기 전에 그렇게 생각했습니다.
그 이유는 명백합니다.
어떤 종류의 "권한"은 맨 처음(10년 전)에 망쳤고 여전히 그가 망칠 수 있다는 것은 누구에게도 떠오르지 않습니다.
https://www.mql5.com/ru/forum/1111/page2780#comment_16886162
그들은 일종의 동의를 하고 끝내기로 약속한 것 같지만, 아니요 - 그들은 득점했습니다. Woz와 지금 거기.
https://www.mql5.com/ru/forum/1111/page2781#comment_16904132


Vitaliy Kuznetsov  
Nikolai Semko :

가장 짧은 방법은 루프에서 비동기 기능을 사용하지 못하도록 하는 iCanvas 성경을 첨부하는 것입니다.
이 경우 캔버스 자체를 사용할 필요가 전혀 없습니다. 차트에 전체적으로 표시되지만 비어 있고 투명합니다.
iCanvas를 사용하지 않고 더 긴 방법이 있다면 이 방법을 이 성경에서 다시 살펴봐야 합니다. 그것은 거기에 있고 실행되지만 이 활동은 희미한 마음을 위한 것이 아닙니다. :))
iCanvas가 하는 일을 간단히 설명하겠습니다.
CHARTEVENT_CHART_CHANGE 이벤트를 포착하고 동일한 모든 비동기 ChartGet 함수를 사용하여 내부 W 구조를 채우는 내부 OnChartEvent 핸들러가 있지만 이 이벤트가 발생할 때 한 번만 수행합니다.
이를 통해 속도를 어느 정도 최적화할 수 있습니다.
또한 이 라이브러리에는 전체 화면으로 확장되고 화면이 변경될 때 조정되는 Canvas 개체가 있습니다.


예를 들어 다음과 같이 세 줄의 코드가 추가되고 많은 줄이 삭제됩니다.

어쨌든 이 알고리즘으로 개체 수를 늘릴 수 있으며 성능에 큰 영향을 미치지 않습니다.

그런 해결책을 주셔서 감사합니다. 실제로 렌더링 속도가 빨라졌습니다. 도서관을 배워야 할 것 같습니다.

다음 뉘앙스를 명확히 하고 싶습니다. 이 공식은 경고와 함께 컴파일됩니다.

y = Canvas.Y(price);

그리고 이것은 경고없이 속도가 약간 떨어집니다.

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

어떤게 더 좋아?)

Maxim Kuznetsov  
Vitaliy Kuznetsov :

그런 해결책을 주셔서 감사합니다. 실제로 렌더링 속도가 빨라졌습니다. 도서관을 배워야 할 것 같습니다.

다음 뉘앙스를 명확히 하고 싶습니다. 이 공식은 경고와 함께 컴파일됩니다.

그리고 이것은 경고없이 속도가 약간 떨어집니다.

어떤게 더 좋아?)

어떤 유형의 "y"가 있습니까?

왜냐하면 int이고 객관적 으로 "속도가 약간 떨어졌다"면 이것은 BUG입니다.

Vitaliy Kuznetsov  
어떤 종류의 Canvas.Y(price);

어떤 유형을 반환합니까
사유: