Как нарисовать текст один под другим с фискированным смещением? Чтобы смещение не менялось при смене таймфрейма.

 
Я разрабатываю стратегию и вот столкнулся с проблемой как размещать текст на чарте?
Мне надо сделать надпись ввиде цифр одну под другой. Как я это делаю показываю внизу ввиде кода
void DrawNumbers() { datetime time; double price; for (int i = 0; i < 13; i++) { string text = i + 1; int index = 1 + Bars - num_index_array[i]; time = Time[index]; if(i = 0) price = Low[index] - Point*shift; //Здесь я сдвигаю текст для нулевого элемента подобрав shift. //Но возникает проблема для различных timeframes else price = Low[index]; DrawText(text, time, price, Yellow); } } string DrawText(string text, datetime time, double price, color font_color) { obj_num++; string object_name = obj_num; int ret = ObjectFind(object_name); PrintLastError(); if(ret != -1) return (0); ObjectCreate(object_name, OBJ_TEXT, 0, time, price); PrintLastError(); ObjectSet(object_name, OBJPROP_TIMEFRAMES, period); PrintLastError(); ObjectSetText(object_name, text, 7, "Arial", font_color); PrintLastError(); return (object_name); }


Посоветуйте как нарисовать одну цифру под другой, и чтобы это расстяние не менялось при смене таймфрема скажем с H1 на M1.
Мне нужно знать маштаб для того, чтобы скажем зная смещение в пикселях (при маштабе 100%) получить это смещение в поинтах по вертикале.
По горизонтале тоже было бы не плохо зная смещение в пикселях получить его в datetime
Может быть вот эта функция мне поможет ObjectGet(obj_name, OBJPROP_SCALE)?
Хотя мне кажется это все ло лишь говорит какой маштаб обекта (50%, 100%, 200% , 300%, ...)а не маштаб в Points-Pixels, datetime-Pixels.
Посоветуйте как быть. Я пока экспеременирую с
string object_name = DrawText(text, time, price, Yellow); int YDist = ObjectGet(object_name, OBJPROP_YDISTANCE) + 7; //смещаю на 7 пикселей ObjectSet(object_name, OBJPROP_YDISTANCE, YDist);

Пока идёт ругань у журнале типа что нет такого свойства unknown object property. Ищю ошибку.

Далее прикрепляю рисунок, объясняющий что я хочу. А я хочу цифру одну под другой нарисовать и чтобы растояние между ними это не менялось при смене таймфремов.
Файлы:
 
Похоже что свойства OBJPROP_YDISTANCE, OBJPROP_CORNER не применимы для объекта типа OBJ_TEXT
ObjectCreate(object_name, OBJ_TEXT, 0, time, price); int YDist = ObjectGet(object_name, OBJPROP_YDISTANCE); int Coner = ObjectGet(object_name, OBJPROP_CORNER);


Я так подумал, потому что свойство OBJPROP_FONTSIZE к объекту OBJ_TEXT применяется и я получаю размер установленного шрифта.

Вообще было бы не плохо если бы была функция для работы с графиками типа
int WindowYPointScale()
Которая бы возвращала количесво пунктов, которые приходятся на один пиксель.
и
int WindowXTimeScale()
которая бы возвращала количество секунд приходящихся на один пиксель.

Это бы позволило рисовать объекты на графике с фиксированным расстоянием между ними.
К примеру, если не хочешь при смене таймфрейма, чтобы твои надписи были слишком далеко от нарисованных баров то задал смещение в пикселях
и узнал сколько это в поинтах или секундах для маштаба 100%.
 
1. Нужно привязаться к текущей ситуации.
Kol_Bars = BarsPerWindow(); // Количество баров в окне High_Win=High[Highest(NULL,0,MODE_HIGH,Kol_Bars,0)]; // Макс. и Миним. цены в окне Low_Win =Low [Lowest (NULL,0,MODE_LOW, Kol_Bars,0)];

2. Расчитывать координаты нижней циферки, имея ввиду % координат в рамках мин. и макс. координат (цен) окна.
(+ учесть размер верхней циферки)
 
SKif:
1. Нужно привязаться к текущей ситуации.
Kol_Bars = BarsPerWindow(); // Количество баров в окне High_Win=High[Highest(NULL,0,MODE_HIGH,Kol_Bars,0)]; // Макс. и Миним. цены в окне Low_Win =Low [Lowest (NULL,0,MODE_LOW, Kol_Bars,0)];

2. Расчитывать координаты нижней циферки, имея ввиду % координат в рамках мин. и макс. координат (цен) окна.
(+ учесть размер верхней циферки)
Интересно. Но вот что это мне даст?
В эксперте я не могу отслеживать скролирование видимой области графика чтобы вычислить координаты циферек согласно текущему маштабу.
А так впринципе да можно было в функции типа
OnChartScroll() координату хай самой верхней свечи и координату лоу самой нижней определить в видимой клиенской области графика.
И взял бы там процент от этой видимой части и вычислил бы смещение для всех цифирь в видимой области.
text_point_shift = (High_Win - Low_Win) / 20;
и изменил бы координаты цифирь согласно текущему маштабу.

Ну я впринципе сделал немного по другому и это более менее приемлимо работает
switch(Period()) { case PERIOD_M1: text_point_shift = Point*2; break; case PERIOD_M5: text_point_shift = Point*3; break; case PERIOD_M15: text_point_shift = Point*4; break; case PERIOD_M30: text_point_shift = Point*5; break; case PERIOD_H1: text_point_shift = Point*6; break; case PERIOD_H4: text_point_shift = Point*7; break; case PERIOD_D1: text_point_shift = Point*7; break; case PERIOD_W1: text_point_shift = Point*9; break; case PERIOD_MN1: text_point_shift = Point*10; break; }

а потом для бара где две цифры 1 и 9 вместе смещаю цифру 9 вниз на text_point_shift в поинтах
price -= text_point_shift; string object_name = DrawText(text, time, price, Yellow);
 
Нельзя жёстко привязываться к поинтам, т.к. цена деления в разных ТФ разная.
Но вот что это мне даст?
Это даст возможность выдерживать одинаковое расстояние в пикселях (% от видимого) между коорд. циферок по вертикали..

Если интересно, вот это посмотри https://www.mql4.com/ru/forum/2773/
Там много подобных решений применяется успешно.
 
SKif:
Нельзя жёстко привязываться к поинтам, т.к. цена деления в разных ТФ разная.
Но вот что это мне даст?
Это даст возможность выдерживать одинаковое расстояние в пикселях (% от видимого) между коорд. циферок по вертикали..

Если интересно, вот это посмотри https://www.mql4.com/ru/forum/2773/
Там много подобных решений применяется успешно.
SKif,
Я конечно разберу твой кладезь интересных решений. Но наверно с завтрашнего дня.
А вот сразу не мог бы подсказать как бы ты сделал решение для простенького примера.
Нужно под каждым баром внизу чуть ниже Low нарисовать цифры - номер текущего бара. причем это растояние не должно сильно меняться, а лучше чтобы оно было фиксированым (скажем пикселей на 5 от лоу каждой свечки).

В коде советника в функции start вызывается DrawNumber
int start() { DrawNumber(); return(0); } void DrawNumber() { string object_name = Bars - 1; ObjectCreate(object_name, OBJ_TEXT, 0, Time[1], Low[1] - 5*Point); ObjectSetText(object_name, object_name, 7, "Arial", RGB(255,0,0)); }


Я написал -5*Point. А ты бы какое решение предложил? Может допишешь код, чтобы написать номер каждого бара на каком-то фиксированом расстоянии ниже Low, и чтобы это расстояние было согласовано с маштабом текушим для D1, H1, M1, ...

Я подумал что ты предлагаешь вот такое решение?
void DrawNumber() { string object_name = Bars - 1; Kol_Bars = BarsPerWindow(); High_Win=High[Highest(NULL,0,MODE_HIGH,Kol_Bars,0)]; Low_Win =Low [Lowest (NULL,0,MODE_LOW, Kol_Bars,0)]; shift = (High_Win-Low_Win) / 25; //25ая часть от видимого ценового диапазона ObjectCreate(object_name, OBJ_TEXT, 0, Time[1], Low[1] - shift); ObjectSetText(object_name, object_name, 7, "Arial", RGB(255,0,0)); }
 
Моя программка вовсе не "кладезь", далека от совершенства.
Я дал ссылку только для того, чтоб можно было посмотреть как это работает при эксплуатации.

Если ты хочешь, чтоб графика на экране выглядела по-человечески, то необх. сделать так, чтоб зрительно (понимай - в пикселях) соблюдалась одна и та же дистанция от границы граф. объекта до Лоу свечи. При этом надо учесть, что это расстояние в пикселях никода не будет одним и тем же неизменным в пунктах. Например, расстояние от минимальной до максимальной цены на Н1 может быть 500п, а на М1 - 15п. 5п на М1 будет занимать треть (!) экрана.

Необходимо вычилить эти пункты для текущего изображения. В каждом конкретном случае это расстояние в пунктах (Distantsiya) будет разным.
Например, такое (1%).
K=0.01; Distantsiya = (High_Win - Low_Win) *K; if (Distantsiya < Point) Distantsiya = Point;


Надо ещё сказать, что при таком подходе один_раз_и_навсегда поставленный графический объект будет соответствовать замыслу в случае, если последующее движение будет прибл. таким, как текущее. Если же курс вдруг возьмёт и резко и сильно сдвинится, то такие объекты (их координаты), всё ещё остающиеся в поле окна, уже не будут соответствовать идее.

Чтобы полностью решить вопрос необходимо перепроверять координаты объектов на каждом тике и при необходимости все зримые объекты перерисовывать. Для этого надо завести массивчик, в кот. хранить все текущие координаты всех видимых объектов. По мере течения времени объекты, кот. находятся за пределами видимости, из массивчика вытеснять, а в начало массива дописывать коорд. вновь поступающих граф. объектов.
Но это хлопотно и, возможно, не нужно.

В общем, смотря как поставить задачу.
 
K=0.01; Distantsiya = (High_Win - Low_Win) *K; if (Distantsiya < Point) Distantsiya = Point;


Я подумал и попробовал этот подход. Этот метод не даёт хорошего результата. Хотя может быть я не до конца просёк ваш подход. Например мы скролируем чарт H1. При каждой появившейся свече и исчезнувшей другой с обратного конца чарта с видимой области, у чарта меняется масштаб по вертикали. То есть получается, что в эксперте мы не сможем правильно изначально рассчитать смещение Distantsiya. Эта дистанция будет менятся при скролинге. Я в прошлых постах где то заблуждался например насчёт масштаба. Сразу в эксперте мы не сможем вычислить смещение, потому как он будет менятся при каждом смещении на одну свечу.
Но сейчас думаю, что если бы разработчики добавили бы функции кроме основных init, start, deinit ещё функции типа onChartScrall. (Это можно уже сейчас сделать в Dll?) то это было бы полезно для графического тображения объектов.
Либо, например, добавить возможность смещения объекта функцией ObjectMove не только на поинты или секунды, а так же на пиксели от первоначальных координат объекта, задаваемых в поинтах и секундах. Тогда МТ4 при скролинге сам пересчитывал бы изначальные координаты поинт-секунды в экранные координаты клинетской области окна (что сейчас и делается) и просто добавлял или отнимал ещё пиксели смещения от первоначальных координат, которые задал программист стратегии привязав например объекты к хай, лоу, клоуз или опен какого то бара.
То есть привязываемся к координатам поинт-секунды, а потом корректируем эти координаты смещением в пикселях.
Это предложение. Возможно разработчики подумают над этим вопросом, а то зачастую объекты трудно рисовать так, чтобы они хорошо выглядели на всех таймфремах. Вот, к примеру, надписи, привязанные к барам, но отстоящие от них, например, на высоту шрифта.
 
Да, действительно, с каждой новой свечкой ситуация будет меняться и значение Distantsiya будет новым.
Тут ещё такая подробность:
советник не знает какую часть истории Вы подтягиваете в окно, а все расчёты ведёт исходя из текущего момента. Поэтому отображённые раз и навсегда граф. объекты будут не всегда отражать картинку "комфортно", если на последних свечах резко изменился верхний или нижний предел шкалы.

Есть ещё возможность использовать фиксированный масштаб цен ( в настройках). Но в этом случае при сильных движениях большая часть графика может легко оказаться за пределами экрана.

Выход один - иметь такой экран, как за спиной ведущего новостей центрального телеканала:)
Причина обращения: