Вопрос по MQL4

 
Всех приветствую,

Хочу перенести описания на горизонтальных линиях вправо.
Пытаюсь реализовать это через ЛАБЕЛ объекты, с привязкой к линиям.
При перемещении графика мышкой, объекты Лагают и подвисают (т.е. если я перемещаю график ровно по вертикали - позиция объектов ЛАБЕЛ вообще не обновляется и они перестают следовать за линиями).
Подскажите пожалуйста, что тут можно сделать?
Документация по MQL5: Типы объектов / Константы, перечисления и структуры
Документация по MQL5: Типы объектов / Константы, перечисления и структуры
  • www.mql5.com
При создании графического объекта функцией ObjectCreate() необходимо указать тип создаваемого объекта, который может принимать одно из значений...
Файлы:
 

В прошлом году я решал подобную задачку. Просто для удобства оперирования с линиями тренда (мне нужно было, чтоб они всегда были строго горизонтальны) я сделал индикатор. Посмотрите мой код (файл приложен)- там при движении графика линии перемещаются вслед за ним. Чуть позже сниму и выложу маленькое видео. Пока же вот участок кода, на который стОит обратить внимание:

// ================================================================================================+
//             =============         БЛОК ОБРАБОТКИ СОБЫТИЙ                =============           |
// ================================================================================================+
void OnChartEvent(const int id,         // идентификатор события   
  const long& lparam,   // параметр события типа long (Координата Х мыши)
  const double& dparam, // параметр события типа double (Координата Y мыши)
  const string& sparam){ // параметр события типа string (Имя объекта, по которому кликнули)
  
        int x=0,y=0,window=0,lastindex=(-1);
        datetime DT=0;
        double PRr=0;
        
        if(id==CHARTEVENT_CLICK){
                CheckLabelAll();
        }
        if(BtnSostoyanie("BtClearTrLine")=="DOWN"){
                if(id==CHARTEVENT_CLICK){
                        DeleteTrLines();
                        BtnPress("BtClearTrLine","UP");
                }
        }
        // ------------- Создаём линию по клику мыши и нажатой кнопке ----------------
        if(BtnSostoyanie("BtBuyTrLine")=="DOWN"){
                //--- нажатие левой кнопкой мышки на графике 
                if(id==CHARTEVENT_CLICK){ 
                        if(CountBuy>0){
                                CountBuy=0;
                                x = (int)lparam;
                                y = (int)dparam;
                                // ------ Инициализируем будущие координаты
                                if(ChartXYToTimePrice(0,x,y,window,TimeRight,PRr)){
                                        lastindex = LastIndex(TimeRight);
                                        if(lastindex<0){
                                                lastindex=5;
                                        }
                                        TimeRight=Time[lastindex];
                                        TimeLeft=Time[lastindex+10];
                                        TimeDotLeft=TimeRight;
                                        TimeDotRight=Time[lastindex-4];
                                        PRr=NormalizeDouble(PRr,DGS);
                                } 
                                // ------------ Зелёная линия -----------------
                                s_TrendLineName=StringConcatenate(SMB,"_",BuyTrendLine,"_Buy_",TimeLocal());
                                if(ObjectFind(s_TrendLineName)<0){
                                        CreateTrendLine(0,s_TrendLineName,0,TimeLeft,PRr,TimeRight,PRr,GreenGroup,STYLE_SOLID,WidthTrendLine,false,true,false,false,0);
                                        ObjectSetInteger(0,"BtBuyTrLine",OBJPROP_STATE,false);// отжимаем кнопку
                                        if(ObjectFind(s_TrendLineName)>(-1)){// линия есть
                                                // --------- Генерируем имя Dot-линии -----------------
                                                s_DotLineName=StringConcatenate("Dot_",s_TrendLineName);
                                                if(ObjectFind(s_DotLineName)<0){
                                                        TimeLeft=TimeRight;
                                                        CreateTrendLine(0,s_DotLineName,0,TimeDotLeft,PRr,TimeDotRight,PRr,GreenGroup,STYLE_DOT,1,false,false,true,false,0);
                                                        s_LabelName=StringConcatenate("LBL_",s_TrendLineName);
                                                        DrawLABEL(Font,FontSize,s_LabelName,DoubleToString(PRr,DGS),3,y-18,CORNER_RIGHT_UPPER,LabelPriceColor);
                                                }
                                        }
                                }
                                else{
                                        ObjectSetInteger(0,"BtBuyTrLine",OBJPROP_STATE,false);// отжимаем кнопку
                                }
                        }
                        else{
                                CountBuy=1;
                        }
                }
        }
        
        if(BtnSostoyanie("BtSellTrLine")=="DOWN"){
                //--- нажатие левой кнопкой мышки на графике 
                if(id==CHARTEVENT_CLICK){ 
                        if(CountSell>0){
                                CountSell=0;
                                x = (int)lparam;
                                y = (int)dparam;
                                // ------ Инициализируем будущие координаты
                                if(ChartXYToTimePrice(0,x,y,window,TimeRight,PRr)){
                                        lastindex = LastIndex(TimeRight);
                                        if(lastindex<0){
                                                lastindex=5;
                                        }
                                        TimeRight=Time[lastindex];
                                        TimeLeft=Time[lastindex+10];
                                        TimeDotLeft=TimeRight;
                                        TimeDotRight=Time[lastindex-4];
                                        PRr=NormalizeDouble(PRr,DGS);
                                }               
                                // ------------ Красная линия ----------------- 
                                s_TrendLineName=StringConcatenate(SMB,"_",SellTrendLine,"_Sell_",TimeLocal());  
                                if(ObjectFind(s_TrendLineName)<0){      
                                        CreateTrendLine(0,s_TrendLineName,0,TimeLeft,PRr,TimeRight,PRr,RedGroup,STYLE_SOLID,WidthTrendLine,false,true,false,false,0);
                                        ObjectSetInteger(0,"BtSellTrLine",OBJPROP_STATE,false);// отжимаем кнопку
                                        if(ObjectFind(s_TrendLineName)>(-1)){// линия есть
                                                // --------- Генерируем имя Dot-линии -----------------
                                                s_DotLineName=StringConcatenate("Dot_",s_TrendLineName);
                                                if(ObjectFind(s_DotLineName)<0){
                                                        CreateTrendLine(0,s_DotLineName,0,TimeDotLeft,PRr,TimeDotRight,PRr,RedGroup,STYLE_DOT,1,false,false,true,false,0);
                                                        s_LabelName=StringConcatenate("LBL_",s_TrendLineName);
                                                        DrawLABEL(Font,FontSize,s_LabelName,DoubleToString(PRr,DGS),3,y-18,CORNER_RIGHT_UPPER,LabelPriceColor);
                                                }
                                        }
                                        else{
                                                ObjectSetInteger(0,"BtSellTrLine",OBJPROP_STATE,false);// отжимаем кнопку
                                        }
                                }
                        }
                        else{
                                CountSell=1;
                        }
                }
        }
        if( id==CHARTEVENT_OBJECT_CLICK){
                LastObjName=sparam;
        }
        //if(id==CHARTEVENT_MOUSE_MOVE){
        if(id==CHARTEVENT_MOUSE_MOVE && LastObjName!=""){
                x = (int)lparam;
                y = (int)dparam;
                if(StringFind(LastObjName,"_Buy_",0)>(-1)){
                        CheckTrendLine(0,LastObjName);// ровняем линию - могли сместить
                        CheckLabelLine(LastObjName);
                }
                if(StringFind(LastObjName,"_Sell_",0)>(-1)){
                        CheckTrendLine(0,LastObjName);// ровняем линию - могли сместить
                        CheckLabelLine(LastObjName);
                        //LastObjName="";
                }
        }
        if(id==CHARTEVENT_OBJECT_DRAG || id==CHARTEVENT_OBJECT_CHANGE || id==CHARTEVENT_OBJECT_ENDEDIT){
        //if(id==CHARTEVENT_OBJECT_DRAG || id==CHARTEVENT_OBJECT_CHANGE || id==CHARTEVENT_OBJECT_ENDEDIT || id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_OBJECT_CLICK){
                if(StringFind(sparam,"_Buy_",0)>(-1)){
                        CheckTrendLine(0,sparam);// ровняем линию - могли сместить
                        CheckLabelLine(sparam);
                }
                if(StringFind(sparam,"_Sell_",0)>(-1)){
                        CheckTrendLine(0,sparam);// ровняем линию - могли сместить
                        CheckLabelLine(sparam);
                }
        }
        if(id == CHARTEVENT_OBJECT_DELETE){
                DeleteObjects(0,StringConcatenate("Dot_",sparam));
                DeleteObjects(0,StringConcatenate("LBL_",sparam));
        }
        ChartRedraw(0);
}       
Файлы:
 

Как-то так.
 
Vitaly Murlenko #:
Посмотрите мой код (файл приложен)- там при движении графика линии перемещаются вслед за ним.

Спасибо за код, посмотрел. У вас MOUSE_MOVE срабатывает только после клика по объекту (через LastObjName), то есть лейблы обновляются только когда линию тащишь. 
А если просто график двигаешь вертикально мышью — Лабелы стоят на месте, отсюда и лаги, такие как у меня были раньше...

Пока что я решил задачу так: 
ловлю CHARTEVENT_CHART_CHANGE для зума/сдвига, плюс MOUSE_MOVE всегда активен (не только после клика по объекту), + таймер на 50мс как страховка. 
ChartRedraw вызываю точечно, а не при любом событии в OnChartEvent — у меня на графике объектов дофига, по этому стараюсь их ставить экономно.
В итоге лейблы ходят за линиями ровно при любом способе перемещения графика — и мышью, и клавишами, и при зуме. 
Проблема с подвисанием ЛАБЕЛов при вертикальном перемещении графика ушла.

В любом случае, спасибо за ответ!

 

Знаете, в таком случае я не понимаю, что же Вы конкретно хотите. Смотрите, моя линия тренда, перемещаемая мышью перемещает за собой и меттку, в которой автоматически меняется цена. В видео это видно. Давайте уйдём от терминов линия, лейба и примем термин "связка объектов" или "группа объектов". Когда в моим индикатором создаёте линию тренда, то на самом деле там не одна, а две линии: сплошная и пунктирная, уходящая лучом вправо. Плюс к этому метка. Я тяну сплошную линию и вслед за ней тянется и пунктирная и метка. То есть, мы перемещаем сразу всю связку объектов. В принципе, не важно, линии это или иные объекты, связанные между собой. Важно другое - перемещается вся группа. Я сейчас сделаю Вам ещё одно видео - там тоже связка объектов (это прямоугольники и метки) - подобие инструмента "Ордер" в терминале TradingView. Посмотрите, там перемещение происходит подобным же образом. Может это видео позволит нам уточнить формулировки.

Итак, объект, как связка, перемещается весь целиком. Но! Вы говорите о перемещении графика, причём, цитирую: "А если просто график двигаешь вертикально мышью..." Вот тут как раз и не понятно, что именно Вы имеете ввиду. График можно перемещать вправо-влево по горизонтали. Но график можно перемещать (масштабировать) и по вертикали - сжимать и растягивать. Смотрите, как только я переместил связку, она автоматически привязывается к координатам цена/время. Листаю график влево и связка уезжает вправо. То есть её координаты относительно свеч не меняются. Когда же сжимаю график по вертикали, у меня сжимается рост свечи и связка съезжает ниже. У меня связка движется относительно краёв экрана. Но она не движется относительно точки привязки к графику. Говоря простым языком, это похоже на то, как я зашёл в автобус - куда он поехал, туда и я поехал. Но что же хотите Вы, поясните.

Сейчас покажу ещё связку, как и обещал.

 

Ну вот вариант:

 

Ваш код:

Строка 26:

bool    g_linesDrawn  = false;

Строки 71-76:

//--- Движение/зум графика — мгновенно пересчитываем Y лейблов
   if (id == CHARTEVENT_CHART_CHANGE && g_linesDrawn)
   {
      UpdateLabelPositions();
      ChartRedraw();
   }

Я думаю, что здесь 

UpdateLabelPositions()

ни когда не выполнится. Есть такая штука - Булева Алгебра. Там есть формулы. Одна из них такая: "А и ложь = ложь", где знак "=" - это эквиваленция. Иными словами: в Вашем случае получается:

if(id == ложь) {
// выполнится только если id = ложь
}
 

Вот ещё участок Вашего кода:

void OnTimer()
{
   if (g_linesDrawn && g_labelsVisible)
   {
      UpdateLabelPositions();
      ChartRedraw();
   }
}

Здесь функция 

UpdateLabelPositions();

не выполнится, ибо ранее проинициализированы ложью обе переменные

g_linesDrawn && g_labelsVisible

Ложь и ложь даст ложь. Вот основные таблицы истинности:


 
Конъюнкция (логическое И) истинна тогда и только тогда, когда оба конъюнкта истинны.
 
Vitaly Murlenko #:
Ну вот вариант:
Вариант с прямоугольниками  -  вот тут всё работает гораздо лучше. Визуально связка жёсткая, сильно ничего никуда не уезжает. 
(точнее плавание объектов в рамках связки приемлемое, учитывая специфику МТ4).
Подозреваю что в этом варианте использованы объекты OBJ_TEXT. Но это не так важно на самом деле.


На счёт выполнения условий, возможно вы не обратили внимания на ХотКей H.
Переменные g_linesDrawn и g_labelsVisible инициализируются false , да — но они меняются на true в функции DrawLines() , которая вызывается по нажатию H. 
После того как линии нарисованы, оба условия выполняются нормально.

Вариант который я описывал в посте #3 - работает хорошо. Возможно я что то делаю не совсем правильно - не спорю. (может что то нужно подчистить)
Файл с решением которое использую сейчас, приложил. (добавлен MOUSE_MOVE и Страховочный таймер 50мс)
И да, вы были правы - связка используются на графике с фиксированным масштабом.
Файлы:
 

Я не стал скачивать Ваш второй файл кода. По-моему у Вас и с первым всё нормально. Посмотрите видео (включите звук в колонках чуть громче - у меня микрофон не очень - не компьютерный). Первые слова невнятны в ролике. Я там сказал: "Доброго времени суток"