Уберите
stop++; if (stop > 100000) break;и все будет хорошо.
Я обычно пишу такой цикл в deinit:
for(i = ObjectsTotal() - 1; i >= 0; i--) { if (StringSubstr("полное имя найденного графического объекта", 0, "количество символов сначала строки") != "те самые символы, которые мы выбирали из строки имени объекта") continue; ObjectDelete("полное имя найденного графического объекта"); }При этом в индикаторе стараюсь создавать объекты с уникальными именами, чтобы при удалении объектов построенных индикатором не снести что-нибудь лишнее.
Проблем с таким кодом пока не возникало.
я просто делаю, почти также как и в вашем решении..
к имени каждого объекта добавляется имя кода (советника, индикатора)
string name = "bla-bla" + "_" + WindowExpertName();
и по вхождению этого имени объекты удаляются..
objectsDelete(WindowExpertName());
с помощью аналогичной (первый ваш кусок кода) функции ..
У меня когда-то возникла проблема присоединения нескольких копий одного индикатора с графикой, но с разн. параметрами, к одному инструменту.
Проблема заключалась как разделить названия объектов, как определить подокно, в ктр. менять объекты в работе или при изменении параметров. Короче, чтобы они не мешали друг дружке сосуществовать.
Понятно, что это крайняя ситуация, но ее решение уж точно позволит не заморачиваться с менее сложными, когда индикаторы разные (обычный случай).
Сделал маленькую библиотечку.
Общие переменные такие:
string NAME[]; // массив имен графических объектов int NameCount; // счетчик графических объектов string ShortName=""; // имя инидкатора для вывода в подокно string _ID; // идентификатор (номер) копии индикатора string _GV="Objects"; // имя гл.терм.переменной
Сначала, при инициализации индикатора нужно получить через гл.терм.переменную его уникальный ID. Функция GetID() в библиотеке. _ID=GetID() в init().
// генерарация идентификатора индикатора string GetID() { int ID=GlobalVariableGet(_GV); // получить существующий идентификатор индикатора ID++; // новый номер GlobalVariableSet(_GV,ID); // новый номер в гл.пер; (если гл.пер. нет, то создается) return(DoubleToStr(ID,0)); // возврат идентификатора индикатора }
Далее, имя объекта создается как ID + [необ.имя] + порядковый номер объекта. Ф-я Name(). Т.е. string ObjName=Name() всегда будет уникальным. Имена ф-я сохраняет в массив string NAME[].
string Name(string obj="") { NameCount++; // счетчик граф. объектов string _Name=_ID+": "+obj+NameCount; // имя объекта = ID индикатора + имя объекта + № гр.объекта ArrayResize(NAME,NameCount); // увеличение массива граф. объектов на 1 NAME[NameCount-1]=_Name; // занесение имени объекта в массив return(_Name); // возврат уникального имени объекта }
При создании объекта нужно знать, в каком подокне это делать. Для этого существует ф-я GetWinNumber(). Неважно сколько одинаковых или разных индикаторов, использующих графику, прикреплено - нужный номер найдется без ошибок, т.к. ф-я сначала подставляет в короткое имя ID индикатора, потом узнает по этому имени номер подокна, а потом восстанавливает оригинальное короткое имя.
// выяснение текущего номера подокна индикатора int GetWinNumber() { IndicatorShortName(_ID); // подмена: имя индикатора = идентификатору (номеру) копии индикатора int win=WindowFind(_ID); // считан номер подокна с именем идентификатора (номера) копии индикатора IndicatorShortName(ShortName); // восстановлено имя индикатора return(win); // возврат номера подокна }
Для удаления созданных индикатором объектов используется ф-я DelObjects(). Используется в deinit() и при пересчете (когда IndicatorCounted() сбрасывается в 0), когда произошла подкачка баров - чтоб графика не сбилась.
// уничтожение объектов void DelObjects() { for(int i=0; i<NameCount; i++) ObjectDelete(NAME[i]); // Стереть созданные индикатором объекты ArrayResize(NAME,1); NameCount=0; // сброс массива и счетчика }
При удалении индикатора с графика нужно освободить его ID в гл.терм.переменной. Для это есть ф-я DeinitObjects(). Вызывается из deinit().
// осовобождение идентификатора void DeinitObjects() { int ID=GlobalVariableGet(_GV); // получить существующий идентификатор (номер) копии индикатора ID--; // уменьшить номер if(ID==0) {GlobalVariableDel(_GV); return;} // если индикаторов,исп.объекты больше нет,удалить гл.пер. GlobalVariableSet(_GV,ID); // новый номер в гл.пер. }В аттаче эта библиотечка и пример ее использования. В примере графически рисуется МАшка с пиковыми значениями по High/Low. Можете сколько угодно сделать подокон с этим инидкатором, потом индивидуально для каждого менять параметры, уничтожать окна - мешать они друг другу не будут.
string Сессия = ""; ... int init() { Сессия = MathRand(); ... int deinit() { Clear(); ... string objname = "Абырвалг " + Сессия; ... void Clear() { int obj_total = ObjectsTotal(); for(int obj = obj_total - 1; obj >= 0; obj--) { string objname = ObjectName(obj); if (StringFind(objname, "Абырвалг " + Сессия) >= 0) ObjectDelete(objname); } }Если я правильно тебя понял. Понималкка отключалась... С прраздником всех... Уфх, отметился...
У меня когда-то возникла проблема присоединения нескольких копий одного индикатора с графикой, но с разн. параметрами, к одному инструменту.
Проблема заключалась как разделить названия объектов, как определить подокно, в ктр. менять объекты в работе или при изменении параметров. Короче, чтобы они не мешали друг дружке сосуществовать.
Понятно, что это крайняя ситуация, но ее решение уж точно позволит не заморачиваться с менее сложными, когда индикаторы разные (обычный случай).
Сделал маленькую библиотечку.
Общие переменные такие:
Сначала, при инициализации индикатора нужно получить через гл.терм.переменную его уникальный ID. Функция GetID() в библиотеке. _ID=GetID() в init().
Далее, имя объекта создается как ID + [необ.имя] + порядковый номер объекта. Ф-я Name(). Т.е. string ObjName=Name() всегда будет уникальным. Имена ф-я сохраняет в массив string NAME[].
При создании объекта нужно знать, в каком подокне это делать. Для этого существует ф-я GetWinNumber(). Неважно сколько одинаковых или разных индикаторов, использующих графику, прикреплено - нужный номер найдется без ошибок, т.к. ф-я сначала подставляет в короткое имя ID индикатора, потом узнает по этому имени номер подокна, а потом восстанавливает оригинальное короткое имя.
Для удаления созданных индикатором объектов используется ф-я DelObjects(). Используется в deinit() и при пересчете (когда IndicatorCounted() сбрасывается в 0), когда произошла подкачка баров - чтоб графика не сбилась.
При удалении индикатора с графика нужно освободить его ID в гл.терм.переменной. Для это есть ф-я DeinitObjects(). Вызывается из deinit().
В аттаче эта библиотечка и пример ее использования. В примере графически рисуется МАшка с пиковыми значениями по High/Low. Можете сколько угодно сделать подокон с этим инидкатором, потом индивидуально для каждого менять параметры, уничтожать окна - мешать они друг другу не будут.Суппер. Ну свинтозавр ты мегамонстр :) Учел всё. Думаю твое решение исчерпывающее. Спасибо.
С новым годом всех :)
Всех с НГ.
Все-таки конфликт имен возможен. Чтобы он гарантированного не возникал, просто не используйте ф-ю DeinitObjects(). Тогда, правда, гл.терм.переменная будет увеличиваться каждый раз при присоединении нового индикатора с графикой, но не будет уменьшаться при его удалении. Но это - фигня. Вряд ли кому-нить удастся достигнуть предела по double (гл.терм переменные имеют тип double) - это до 1.7 * e308.)))
![MQL5 - Язык торговых стратегий для клиентского терминала MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Господа, скажите, как вы удаляете объекты индикатора. При этом так, чтобы объекты созданные другими индикаторами или те что были вручную созданы оставались?
Я это делаю так, как посоветовали здесь https://forum.mql4.com/ru/12206:
void DeleteObjects()
{
int stop;
string name;
for(int n=ObjectsTotal()-1;n>=0;n--)
{
// получаем имя объекта
name = ObjectName(n);
// удаляем только те, имя которых начинается с префикса в переменной GOGP
if (StringFind(name, GOGP, 0)==0) ObjectDelete(name);
stop++;
if (stop > 100000) break;
}
Comment("stop=" + stop);
}
Однако, есть проблема, которая заключается в том, что фактически эта функция прерывается по таймауту, если есть объекты не принадлежащие индикатору по признаку префикса в имени объектов. Как все-таки сделать красиво, но чтобы не считать созданные объекты??
Сразу приведу мой начальный вариант, который более громоздкий, но все-таки работает (состоит из двух процедур):
// удаление объектов на графике, которые принадлежат данному индикатору.
void DeleteObjectsN()
{
// Для перехвата последующих ошибок удаления обнуляем предыдущие ошибки которые могли быть.
int err = GetLastError();
// Максимальное число попыток удаления объектов. Обычно делает до 20.
int MaxTryCount = 1000;
// Делаем цикличное удаление до полного отсутствия ошибок.
for (int i=0;i<MaxTryCount;i++)
{
DeleteObjects2();
err = GetLastError();
if (err == 0) break;
}
// очищаем коммент
//Comment("");
return(0);
}
// это удаляет объекты, но нужно делать много раз, 20 например...
// происходит какой-то глюк, хотя при следующем подходе все нормально удаляется.
void DeleteObjects2()
{
int obj_total=ObjectsTotal();
string name;
for(int n=0;n<obj_total;n++)
{
// получаем имя объекта
name = ObjectName(n); // здесь происходит ошибка 4202 ERR_OBJECT_DOES_NOT_EXIST,
// которая ведет за собой ошибку удаления
// удаляем только те, имя которых начинается с префикса в переменной GOGP
// и чтобы имя не пустое было, а то это влечет за собой следующую ошибку 4202 или 4204
if (StringFind(name, GOGP, 0)==0 && name!="") ObjectDelete(name);
}
}