АвторСообщение



Сообщение: 43
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 16.12.16 05:39. Заголовок: Паттерны ПрайсЭкшен через структуру


Игорь добрый день!
Перенесу сюда свои мытарства с перепрограммированием индикатора по паттернам под свои нужды. В той ветке я показал, что кое-какие сдвиги к получению желаемого мной результата есть. В текущем варианте как вы видели по картинкам он уже отрисовывает паттерны и их цели, способен перекрасить паттерны, если его таргет пробит. Вопрос по удалению перекрытых паттернов пока откладываю на потом, поскольку возник более актуальный. Повторю здесь кусок кода, где происходят главные события с паттернами:
Скрытый текст

Отображает он все как мне хотелось бы. При наведении мышки на паттерн отображает информацию из функции GetUniqueID:

 цитата:
string GetUniqueID(const Pattern & pattern, string middlePart)
{

return(PREFIX + EnumToString(pattern.patternName)+EnumToString(pattern.getTarget)+"_"
+EnumToString(pattern.patternType)+ middlePart + string(Time[pattern.rightBarIndex]));
}


Но тут где-то собака зарылась, не пойму относительно отображения EnumToString(pattern.getTarget), которая определяется отдельной функцией (кстати подобными строками перекрашиваются паттерны):

 цитата:
int IsActualPattern(Pattern &pattern)
{
for(int i = ArraySize(g_patterns)-1; i >= 0; i--)
{
if(g_patterns.patternType == BEAR_TYPE)
{
for(int k = g_patterns.rightBarIndex-1; k >= 0; k--)
{
if(iLow(NULL, 0, k) < g_patterns.patternTarget)
g_patterns.getTarget = WORKED;
else
g_patterns.getTarget = ACTUAL;
}
}
if(g_patterns.patternType == BULL_TYPE)
{
for(int k = g_patterns.rightBarIndex-1; k >= 0; k--)
{
if(iHigh(NULL, 0, k) > g_patterns.patternTarget)
g_patterns.getTarget = WORKED;
else
g_patterns.getTarget = ACTUAL;
}
}
}
return (g_patterns[ArraySize(g_patterns)-1].getTarget);
}


Так вот... Eсли медвежий паттерн отработан (WORKED) - то окрашивается он как отработанный, и в подписи к нему EnumToString(pattern.getTarget) пишет WORKED, а вот с бычьими почему-то не пишет... окрашивает как отработанный, но в подписи и в принте пишет что он актуальный (см. рис). Как побороть это недоразумение? Сдается мне что тут вина в implicit enum conversion в строке
g_patterns[patternArray].getTarget = getTarget, его энум
Скрытый текст

Кроме этого таких предупреждений еще два штуки есть по коду в строках:
g_patterns[patternArray].patternType = patternDir, его Энум выглядит так
Скрытый текст

и
g_patterns[patternArray].patternName = patternName, его энум
Скрытый текст

Ну и все они в структуре объявлены и инициализированы вот так
patternType = NONE_TYPE;
patternName = NONE_INDEX;
getTarget = NONE;
И на всякий случай функция GetData
Скрытый текст

Ткните, плиз носом, как победить этот недуг


Просмотрев немного по истории, точной закономерности не выявил, но вот покажу участок, где стрелками показаны два по рассраске отработанных бычьих паттерна, между ними 8 свечей (две стрелки указывают на один и тот паттерн). Но подписи у них разные... тот что ниже слева - пишет WORKED, а тот что через 8 свечей справа - ACTUAL.


Чо к чему... не пойму А главное как так-то? Может в коде какого дополнительного условия не хватает в функции IsActualPattern? Или это не понятные примудрусти какие-то в функции строки подписи?
Скрытый текст



Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 87 , стр: 1 2 3 4 5 6 All [только новые]







Сообщение: 2396
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 16.12.16 18:57. Заголовок: evbut пишет: Но тут..


evbut пишет:

 цитата:
Но тут где-то собака зарылась, не пойму относительно отображения EnumToString(pattern.getTarget), которая определяется отдельной функцией (кстати подобными строками перекрашиваются паттерны):


Проблема в том, что нужно прерывать цикл после того, как найден пробой цели. А у Вас после этого проверяются свечи далее. Они могут не достигать цели. В итоге паттерн будет снова подписан как WORKED. Таким образом, проблема будет не только с бычьими, но и с медвежьими паттернами.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 44
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 17.12.16 13:49. Заголовок: Scriptong пишет: Та..


Scriptong пишет:

 цитата:
Таким образом, проблема будет не только с бычьими, но и с медвежьими паттернами.


Оно так и есть, я лишь на примере бычьих показал... Какими-то участками то бычьи, то медвежьи не верно запоминает (( Не думал, что один и тот же код по разному воспринимается переменными, в частности enum...
В общем и эта проблема решилась... Оставил код определения факта отработки такой же как и для цвета, а энум оставил такой

 цитата:
enum ENUM_GET_TARGET
{
ACTUAL, //Актуальный
WORKED
};


Ведь по хорошему нет же паттерна с типом NONE, неопределенным цветом, с неизвесным таргетом и прочими отсутствующими характеристиками в базе данных паттерна.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2397
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 19.12.16 16:23. Заголовок: evbut пишет: В обще..


evbut пишет:

 цитата:
В общем и эта проблема решилась... Оставил код определения факта отработки такой же как и для цвета, а энум оставил такой


Перечисление в данном случае не при чем. Не нужно было его менять. NONE - это тип неопределенного паттерна. Он необходим для правильной работы индикатора.
По всей видимости, Вы не поняли, в чем именно проблема. В таком случае попытаюсь объяснить еще раз.
В приведенном коде видно, что проверка достижения цели паттерна происходит на всем участке истории от момента формирования паттерна до нулевого бара. И это правильно. Но упущен важный момент: когда найдено достижение цели паттерна, требуется прекращение дальнейшего хода цикла.
К примеру, найден паттерн на баре с индексом 5. После этого запускается цикл поиска достижения цели от бара с индексом 4 до текущего бара (с индексом 0). Допустим, цель достигнута на 3-ем баре, а после этого цена откатила и больше не достигала цели. Приведенный код поставит на 3-ем баре признак WORKED, но потом перейдет к барам 2, 1 и 0, где цель не достигнута, и вернет признак ACTUAL обратно. А нужно сделать так, чтобы признак ACTUAL уже не мог быть установлен, если признак WORKED имеется.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 47
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 19.12.16 16:42. Заголовок: Scriptong пишет: По..


Scriptong пишет:

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


Этот момент я понимаю, не вразумлю только в каком месте цикла нужно брикнуть, чтоб срабатывала проверка Новый обнаруженный паттерн обозначает как ACTUAL, но не перепроверяется на актуальность база паттернов ладе на новой свече... Видимо для этого дела лучше делать отдельную функцию ведь эта проверка всего лишь условие не являющееся обязательным - if(ShowWorkedpattern) - чтобы вносить ее в БД

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2399
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 21.12.16 07:24. Заголовок: evbut пишет: Этот м..


evbut пишет:

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


Как только обнаружено достижение цели (WORKED) нужно выходить из цикла, чтобы не перезаписать вновь значение ACTUAL. Хотя в Вашем случае более уместно добавить проверку в цикл k:

 цитата:
int IsActualPattern(Pattern &pattern)
{
for(int i = ArraySize(g_patterns)-1; i >= 0; i--)
{
if(g_patterns.patternType == BEAR_TYPE)
{
for(int k = g_patterns.rightBarIndex-1; k >= 0 && g_patterns.patternTarget == ACTUAL; k--)
{
if(iLow(NULL, 0, k) < g_patterns.patternTarget)
g_patterns.getTarget = WORKED;
else
g_patterns.getTarget = ACTUAL;
}
}
if(g_patterns.patternType == BULL_TYPE)
{
for(int k = g_patterns.rightBarIndex-1; k >= 0 && g_patterns.patternTarget == ACTUAL; k--)
{
if(iHigh(NULL, 0, k) > g_patterns.patternTarget)
g_patterns.getTarget = WORKED;
else
g_patterns.getTarget = ACTUAL;
}
}
}
return (g_patterns[ArraySize(g_patterns)-1].getTarget);
}



Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 48
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 21.12.16 05:45. Заголовок: Scriptong пишет: К ..


Scriptong пишет:

 цитата:
К примеру, найден паттерн на баре с индексом 5. После этого запускается цикл поиска достижения цели от бара с индексом 4 до текущего бара (с индексом 0). Допустим, цель достигнута на 3-ем баре, а после этого цена откатила и больше не достигала цели. Приведенный код поставит на 3-ем баре признак WORKED, но потом перейдет к барам 2, 1 и 0, где цель не достигнута, и вернет признак ACTUAL обратно. А нужно сделать так, чтобы признак ACTUAL уже не мог быть установлен, если признак WORKED имеется.


А принты не говорят об этом, а показывают отработан паттерн. Вывел специально текстовое описание паттерна, которое показывает тип паттерна и его отработанность... Все говорит о том, что Ваша верная логическая цепочка не работает дальше момента, когда цель достигнута на 3-ьем баре, на барах со 2 по 0 факт WORKED не переписывается. Или я самообманываюсь?


 цитата:

//+-------------------------------------------------------------------------------------+
//| Актуален ли паттерна |
//+-------------------------------------------------------------------------------------+
ENUM_GET_TARGET IsActualPattern(Pattern &pattern)
{
for(int i=ArraySize(g_patterns)-1; i>=0; i--)
{
if(g_patterns.patternType==BEAR_TYPE)
{
for(int k=g_patterns.rightBarIndex; k>=0; k--)
{
if(iLow(NULL,0,k)<g_patterns.patternTarget)
g_patterns.getTarget=WORKED;
}
}
if(g_patterns.patternType==BULL_TYPE)
{
for(int k=g_patterns.rightBarIndex; k>=0; k--)
{
if(iHigh(NULL,0,k)>g_patterns.patternTarget)
g_patterns.getTarget=WORKED;
}
}
}
return (g_patterns[ArraySize(g_patterns)-1].getTarget);
}


Объясните почему в энуме по отработке стоит оставить NONE? Ведь по сути у паттерна не может быть такого состояния. Как только паттерн обнаружился он по факту ACTUAL пусть даже на долю секунды на минутном графике при выходе новостей и бешенной скорости изменения цены.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2400
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 21.12.16 07:26. Заголовок: evbut пишет: Объясн..


evbut пишет:

 цитата:
Объясните почему в энуме по отработке стоит оставить NONE? Ведь по сути у паттерна не может быть такого состояния.


В момент инициализации паттерна такое значение может быть. То есть когда паттерна нет (он не ACTUAL и не WORKED).

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 45
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 19.12.16 03:20. Заголовок: Игорь, подскажите, к..


Игорь, подскажите, как заставить индикатор рисовать в тестере? Тяжко на минутном графике даже выжидать как он работает в реале ))
Но таки высмотрел такой момент.Функцию FindAndShowPatterns малость переделал
Скрытый текст

Как бы функция работает и новые паттерны рисует, и алерт срабатывает но...- почему-то не перекрашивает паттерны в цвет отработанных в режиме онлайн, только после обновления графика или переключением таймфреймов. В OnCalculate вот так прописано

 цитата:
int total;
int limit=GetRecalcIndex(total,rates_total,prev_calculated); // Определим первый расчетный бар

for(int i=limit; i>0; i--) // Обработаем все новые бары
{
FindAndShowPatterns(i);
ChartRedraw();
}
return rates_total;


НЕ пойму почему, подскажите, пожалуйста

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2398
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 19.12.16 16:25. Заголовок: evbut пишет: НЕ пой..


evbut пишет:

 цитата:
НЕ пойму почему, подскажите, пожалуйста


Скорее всего, проблема в функции отображения паттерна. Покажите ее код (ShowRectangle)

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 46
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 19.12.16 16:38. Заголовок: Scriptong пишет: По..


Scriptong пишет:

 цитата:
Покажите ее код (ShowRectangle)



 цитата:
void ShowRectangle(string name,datetime time1,double price1,datetime time2,
double price2,string toolTip,color clr)
{
if(ObjectFind(name)<0) // Если объект не существует
{
ObjectCreate(0,name,OBJ_RECTANGLE,0,time1,price1,time2,price2);
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
ObjectSetInteger(0,name,OBJPROP_WIDTH,LineWidth);
ObjectSetInteger(0,name,OBJPROP_STYLE,LineStyle);
ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
ObjectSetInteger(0,name,OBJPROP_BACK,FillRectangle);
ObjectSetString(0,name,OBJPROP_TOOLTIP,toolTip);
return;
}
ObjectMove(name,0, time1, price1); // Перемещение существующего объекта
ObjectMove(name, 1, time2, price2); // Перемещение существующего объекта
}



Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2401
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 21.12.16 07:28. Заголовок: evbut пишет: Покажи..


evbut пишет:

 цитата:
Покажите ее код (ShowRectangle)


Как я и предполагал, здесь недоработка. Функция не содержит кода, который изменяет цвет объекта, если он уже создан. Посмотрите внимательно: если объект уже существует, то будет изменена только его цена, но не цвет. Нужно в таких случаях изменять еще и цвет:

 цитата:

void ShowRectangle(string name,datetime time1,double price1,datetime time2,
double price2,string toolTip,color clr)
{
if(ObjectFind(name)<0) // Если объект не существует
{
ObjectCreate(0,name,OBJ_RECTANGLE,0,time1,price1,time2,price2);
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
ObjectSetInteger(0,name,OBJPROP_WIDTH,LineWidth);
ObjectSetInteger(0,name,OBJPROP_STYLE,LineStyle);
ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
ObjectSetInteger(0,name,OBJPROP_BACK,FillRectangle);
ObjectSetString(0,name,OBJPROP_TOOLTIP,toolTip);
return;
}
ObjectMove(name,0, time1, price1); // Перемещение существующего объекта
ObjectMove(name, 1, time2, price2); // Перемещение существующего объекта
ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
}



Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 51
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 27.12.16 08:52. Заголовок: Scriptong пишет: Ка..


Scriptong пишет:

 цитата:
Как я и предполагал, здесь недоработка. Функция не содержит кода, который изменяет цвет объекта, если он уже создан. Посмотрите внимательно: если объект уже существует, то будет изменена только его цена, но не цвет. Нужно в таких случаях изменять еще и цвет:


Добавил не достающую строку, всю равно не перекрашивает (( Вся перекраска происходит только после обновления графика или в момент инициализации индикатора. Такое ощущение, что чего-то не хватает, где-то чего не учел я - не соображу... уже голову наизнанку вывернул. Уже и функцию цвета переделал под манер функции проверки ACTUAL или WORKED паттерн (ее пока оставил, ибо не удобно следить). Видно надо перекур сделать ))

Скрытый текст



Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2408
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 27.12.16 19:38. Заголовок: evbut пишет: Добави..


evbut пишет:

 цитата:
Добавил не достающую строку, всю равно не перекрашивает (( Вся перекраска происходит только после обновления графика или в момент инициализации индикатора. Такое ощущение, что чего-то не хватает, где-то чего не учел я - не соображу... уже голову наизнанку вывернул. Уже и функцию цвета переделал под манер функции проверки ACTUAL или WORKED паттерн (ее пока оставил, ибо не удобно следить). Видно надо перекур сделать ))


Давайте тогда уже весь индикатор (приаттачьте через dropmefiles или любой другой ресурс). Ведь по обрывку кода трудно что-то сказать.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 52
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 28.12.16 02:12. Заголовок: Scriptong пишет: Да..


Scriptong пишет:

 цитата:
Давайте тогда уже весь индикатор


Тынц Ссыль действительна 6 дней

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2412
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 31.12.16 20:46. Заголовок: evbut пишет: Тынц С..


evbut пишет:

 цитата:
Тынц Ссыль действительна 6 дней


Скачал. Посмотрю уже в следующем году

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 54
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 01.01.17 02:31. Заголовок: evbut пишет: Посмот..


evbut пишет:

 цитата:
Посмотрю уже в следующем году


С Новым Годом, Игорь! Спасибо Вам за неизменную поддержку и Ваш профессионализм в прошлом году! В новом году желаю успеха в реализации Ваших задумок, благополучия и мирного неба Вам и вашей семье!

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2418
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 05.01.17 17:53. Заголовок: evbut пишет: Тынц С..


evbut пишет:

 цитата:
Тынц Ссыль действительна 6 дней


Посмотрел. Не увидел в коде участка, отвечающего за перерисовку паттерна. Так, функция ProcessBar обслуживает только новые бары. Она никогда не повторяет расчет одного и того же бара. Поэтому паттерн может быть только найден. Его дополнительная проверка не производится.

Возможно проверка задумывалась в функции IsActualPattern(), но эта функция нигде в коде не вызывается. Даже, если она будет вызвана, то это ни к чему не приведет, т. к. функция меняет лишь статус паттерна, но не производит его перерисовку.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 55
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 07.01.17 18:36. Заголовок: Scriptong пишет: Во..


Scriptong пишет:

 цитата:
Возможно проверка задумывалась в функции IsActualPattern(), но эта функция нигде в коде не вызывается. Даже, если она будет вызвана, то это ни к чему не приведет, т. к. функция меняет лишь статус паттерна, но не производит его перерисовку.



Собственно да, один из вариантов реализации отображения отработки паттернов было как раз через эту функцию, что-то в этом духе

 цитата:
void ReDrawPattern(Pattern &pattern)
{
IsActualPattern(pattern);
if(ShowWorkedPattern && pattern.getTarget == WORKED &&
(pattern.patternType == BEAR_TYPE || pattern.patternType == BULL_TYPE))
{
pattern.patternColor = WorkColor;
}
else
{
if(pattern.patternType == BEAR_TYPE)
pattern.patternColor = RegcolorBears;
else
pattern.patternColor = RegcolorBulls;
}
ShowPatterns(pattern);


Далее в OnCalculate так прописал

 цитата:
int limit=GetRecalcIndex(total); // Определим первый расчетный бар

for (int i = limit; i > 0; i--)
{
FillPatternsDB(i); //функция наполнения базы паттернов типа void

for(int k = ArraySize(g_patterns)-1; k>=0; k--)
ReDrawPattern(g_patterns[k]); //собственно отрисовка
}

WindowRedraw();


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

Решение кажется нашлось... в функции GetUniqueID было внесено отображение факта отработки паттерна. ТАк вот получалось, что индикатор не находил прямоугольник патерна с подписью ACTUAL, потому что он уже был WORKED, поэтому рисовал его поновой в другом месте..




Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2423
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 13.01.17 21:07. Заголовок: evbut пишет: Собств..


evbut пишет:

 цитата:
Собственно да, один из вариантов реализации отображения отработки паттернов было как раз через эту функцию, что-то в этом духе

 цитата:
void ReDrawPattern(Pattern &pattern)
{
IsActualPattern(pattern);
if(ShowWorkedPattern && pattern.getTarget == WORKED &&
(pattern.patternType == BEAR_TYPE || pattern.patternType == BULL_TYPE))
{
pattern.patternColor = WorkColor;
}
else
{
if(pattern.patternType == BEAR_TYPE)
pattern.patternColor = RegcolorBears;
else
pattern.patternColor = RegcolorBulls;
}
ShowPatterns(pattern);


Далее в OnCalculate так прописал


Ну это уж совсем никудышное решение. Во-первых, производится повторение одних и тех же действий (вызов функции FillDBPatterns() теперь будет дважды на одном и том же баре и, приводит к дублированию паттернов в массиве - см. журнал). Во-вторых, дважды производится определение отработки паттерна (логика размазана по двум функциям RecolorPattern() и ReDrawPattern()), что затрудняет понимание кода.

Также в процессе просмотра кода увидел основную проблему: при нахождении паттерна запонимаются номера баров, где он найден (члены leftBarIndex и rightBarIndex структуры Pattern). При таком подходе требуется поддерживать номера баров в дальнейшем, т. к. номер бара - не уникальный идентификатор. Номера баров изменяются в момент прихода нового бара. В итоге тот бар, который сохранен для паттерна оказывается невалидным. Поэтому нужна поддержка индексов. Или же, лучший подход, запоминать не индекс бара, в время открытия баров. Это уже уникальные данные, которые никогда не изменяться.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 50
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 22.12.16 08:16. Заголовок: Игорь, подскажите, д..


Игорь, подскажите, достаточно ли будет на этом этапе в функции наполнения БД паттернов

 цитата:
int patternArray=ArraySize(g_patterns);
for (int i = patternArray - 1; i >= 0; i--)
if (g_patterns.patternType == newPattern &&
g_patterns.patternName == newPatternName &&
g_patterns.leftBarIndex == startBar &&
g_patterns.rightBarIndex == endBar
)
return FUNCTION_RESULT_ALRIGHT;


прописать для проверки только эти характеристики паттерна или же нужно проверить все согласно прописанного в структуре (за исключением patternTarget, getTarget и patternColor?

 цитата:
ENUM_PATTERN_TYPE patternType; // Тип паттерна (бычий, медвежий)
ENUM_PATTEN_NAME patternName; // Индекс имени паттерна
ENUM_GET_TARGET getTarget; // Отработан ли патерна
int leftBarIndex; // Индекс левого бара паттерна
int rightBarIndex; // Индекс правого бара паттерна
double patternLowPrice; // Нижняя цена паттерна
double patternHighPrice; // Верхняя цена паттерна
double patternHeight; // Высота паттерна
double patternTarget; // Уровень цели бычьего паттерна
color patternColor; // ЦВет паттерна


И еще несколько вопросов по коду функции из инидкатора Всплеск и полка

 цитата:
ShowIndicatorData(int limit, int total)
{
if (limit > 1)
{
ArrayResize(g_patterns, 0, ARRAY_RESERVE_SIZE);
g_lastBuyPatternRegFractalTime = 0;
g_lastSellPatternRegFractalTime = 0;
}

if (limit == 1)
for (int i = ArraySize(g_patterns) - 1; i >= 0; i--)
{
g_patterns.leftBarIndex++;
g_patterns.rightBarIndex++;
}

for (int i = limit; i >= 0; i--)
if (!ProcessBar(i))
return false;


Под limit подразумевается количество баров или собственно ограничение в барах? Да и в целом я правильно понимаю результат этой функции:
при limit > 1 задаем новый размер массива паттернов, при limit == 1 - изменяем номера баров границы паттернов, и в последнем случае отрисовываем что желаем?

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2402
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 26.12.16 13:25. Заголовок: evbut пишет: Игорь,..


evbut пишет:

 цитата:
Игорь, подскажите, достаточно ли будет на этом этапе в функции наполнения БД паттернов
прописать для проверки только эти характеристики паттерна или же нужно проверить все согласно прописанного в структуре (за исключением patternTarget, getTarget и patternColor?


Пока суть вопроса неясна. Конкретизируйте, пожалуйста.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2403
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 26.12.16 13:33. Заголовок: evbut пишет: Под li..


evbut пишет:

 цитата:
Под limit подразумевается количество баров или собственно ограничение в барах?


В данном случае то, что представляет собой переменная limit, описано в функции OnCalculate:

 цитата:
int total;
int limit = GetRecalcIndex(total, rates_total, prev_calculated);

if (!ShowIndicatorData(limit, total))
g_activate = false;


В свою очередь, GetRecalcIndex прокомментирована: Determination of bar index which needed to recalculate. Это означает, что переменная limit получает индекс бара, с которого на текущем тике необходимо вычислять значения индикатора.
Так, при первом запуске индикатора limit получит индекс самого левого бара в истории минус 2 (ratesTotal - 3), если значение параметра "Количество баров отображения" равно 0. В пртивном случае переменная limit будет равна значению этого параметра.
При повторном вызове функции OnCalculate индикатора значение limit будет равно 0, если на текущем баре уже были вычисления, и 1, если образовался новый бар. Больше 1 при повторном вызове OnCalculate переменная limit будет только в случае подкачки истории котировок.
Такой подход позволяет оптимизировать работу индикатора: с каждым новым тиком производится перерасчет только вновь поступивших данных. В противном случае индикатор на каждом тике производил бы перерасчет всей имеющейся истории.


Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 53
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 28.12.16 05:42. Заголовок: Scriptong пишет: Та..


Scriptong пишет:

 цитата:
Такой подход позволяет оптимизировать работу индикатора: с каждым новым тиком производится перерасчет только вновь поступивших данных. В противном случае индикатор на каждом тике производил бы перерасчет всей имеющейся истории.


Выходит проблема не перекрашивания отработанных паттернов зарыта в этой области. Значит саму функцию пересчета баров необходимо сделать так, чтобы на каждом новом баре индикатор в массиве паттернов искал все ACTUAL и от самого левого из них перепроверил их актуальность.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 56
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 11.01.17 03:47. Заголовок: Игорь, не подскажите..


Игорь, не подскажите, почему при смене тайм-фрейма остаются элементы с которого ушел?


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2424
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 13.01.17 21:17. Заголовок: evbut пишет: Игорь,..


evbut пишет:

 цитата:
Игорь, не подскажите, почему при смене тайм-фрейма остаются элементы с которого ушел?


У меня такое не наблюдается. Проверил на последней версии (со вставкой приведенного Вами кода).

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 57
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 13.01.17 22:34. Заголовок: Scriptong пишет: У ..


Scriptong пишет:

 цитата:
У меня такое не наблюдается.


Странно очень... Такое отмечается, когда переключаешься с меньшего фрейма на больший. Однако в функцию ShowIndicatorData прописал

 цитата:
if(limit > 1)
ArrayResize(g_patterns,0);



и кажется перестало такое безобразие мельтешить... Не критично конечно, но мешает.

Такой еще момент. Решил добавить опционально удаление перекрытых паттернов. Код такой

 цитата:
//+-----------------------------------------------------------------------------+
//| Process specify pattern |
//+-----------------------------------------------------------------------------+
bool IsNeedToDeletePattern(const Pattern &pattern, int index)
{
if(OverLaidPattern)
return false;

for (int i = index; i < pattern.leftBarIndex; i++)
{
if(NamePattern(i) < 0)
{ return false;
i--; }
}
return true;
}
//+-----------------------------------------------------------------------------+
//| Delete specify element from array |
//+-----------------------------------------------------------------------------+
template<typename T>
void DeleteElementFromArray(T &array[], int elementToDelete)
{
int arraySize = ArraySize(array);
if (arraySize == 0)
return;

array[elementToDelete] = array[arraySize - 1];
ArrayResize(array, arraySize - 1, ARRAY_RESERVE_SIZE);
}
//+-----------------------------------------------------------------------------+
//| Process on overlaid pattern |
//+-----------------------------------------------------------------------------+
void ProcessPatterns(int index)
{
for (int i = ArraySize(g_patterns) - 1; i >= 0; i--)
if (IsNeedToDeletePattern(g_patterns, index-1))
DeleteElementFromArray(g_patterns, i);
}


Судя по картинкам - удаляет те двухсвечные, паттерны, которые находятся как бы внутри трехсвечного паттерна. Однако "чистка" среди трехсвечных не происходит (подчеркнул на картинке явное наложение. По идее синий паттерн должен быть удален). Каким образом заставить и такие участки удалять или где-то в коде косякнул?



Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2425
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 17.01.17 17:24. Заголовок: evbut пишет: Странн..


evbut пишет:

 цитата:
Странно очень... Такое отмечается, когда переключаешься с меньшего фрейма на больший. Однако в функцию ShowIndicatorData прописал


Проверил, переключившись а М1 на Н1. Все ОК.

evbut пишет:

 цитата:
и кажется перестало такое безобразие мельтешить... Не критично конечно, но мешает.


Это, кстати, правильный ход. Только лучше такой код разместить в GetRecalcIndex() после строки ObjectsDeleteAll(). Ведь объекты удаляются, а массив g_patterns в итоге будет содержать паттерны-дубликаты.

evbut пишет:

 цитата:
Такой еще момент. Решил добавить опционально удаление перекрытых паттернов. Код такой


Нужно знать, откуда вызывается этот код. В самом же коде есть логическое упущение - в функции IsNeedToDeletePattern() проверяется только совпадение правых краев паттернов, а далее - нет.
Кстати, в чем смысл такой конструкции?

 цитата:
if(NamePattern(i) < 0)
{ return false;
i--; }


Во-первых, после return ничего не может выполняться. Во-вторых, если допустить, что требуется декремент значения i при выполнении условия NamePattern, то все равно смысла нет - происходит выход из функции, значение переменной i теряется. Или же декремент должен был быть за фигурной скобкой? Но тогда получим бесконечный цикл...



Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 58
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 18.01.17 02:18. Заголовок: Scriptong пишет: Кс..


Scriptong пишет:

 цитата:
Кстати, в чем смысл такой конструкции?


В нее заложен смысл, что если нет именованного паттерна, то и проверять не имеет смысла.


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2427
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 24.01.17 11:03. Заголовок: evbut пишет: В нее ..


evbut пишет:

 цитата:
В нее заложен смысл, что если нет именованного паттерна, то и проверять не имеет смысла.


Так а зачем после return происходит декремент? Ведь после return ничего не может выполняться в том же блоке. Возможно, скобкой ошиблись. Но тогда, когда исправите положения скобок, получите зависание индикатора.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 59
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 19.01.17 18:50. Заголовок: И снова здрасьте... ..


И снова здрасьте... С удалением перекрытых паттернов еще однако разгребать и разгребать... Но вот решил сделать выбор отображения паттернов по отдельности, а не кучей... Уже и не помню ту версию что высылал вам... В общем функция ShowIndicatorData выглядит теперь так

 цитата:
void ShowIndicatorData(int limit, int total)
{
if(limit > 1)
ArrayResize(g_patterns,0);

for (int i = limit; i > 0; i--)
{
FillPatternsDB(i);
ProcessPatterns(i);
for(int j = ArraySize(g_patterns)-1; j >= 0; j--)
{
if((IsShowOVBPattern && g_patterns[j].patternName == OVB_) ||
(IsShowPPRPattern && g_patterns[j].patternName == PPR_) ||
(IsShowRailsPattern && g_patterns[j].patternName == RAILS_))
ReDrawPattern(g_patterns[j]);
}
}
}


Включаю по отдельности отображение то рельс, то ППР... И вот при отображении только паттерна Рельсы на некоторых участках встречается вот такое как для бычьих так и для медвежьих направлений (см рис), что совсем не понятно откуда всплывает - Прямоугольник показывает ППР да и выглядит это комбинация свечей как ППР, а в подписи Рельсы (( В настройках параметры Рельс стоят 20 и 10



Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2426
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 24.01.17 11:01. Заголовок: evbut пишет: Уже и ..


evbut пишет:

 цитата:
Уже и не помню ту версию что высылал вам


Вот и мне трудно поддерживать именно тот исходник, с которым Вы работаете, отслеживая изменения по Вашим постам. Пожалуйста, прикрепляйте свою последнюю версию, с которой работаете. Тогда легче будет поддерживать предметный разговор. А иначе я просто теряюсь в догадках.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 60
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 25.01.17 15:15. Заголовок: Scriptong пишет: Во..


Scriptong пишет:

 цитата:
Вот и мне трудно поддерживать именно тот исходник,


ЗДЕСЬ можно взять крайнюю версию индикатора... Всё перерыл в коде... не найду отчего так отрисовывает и подписывает (( Все функции поиска паттернов взяты из вашего индикатора, за исключением WRB. Поглядите своим опытным глазом, пожалуйста... Ссылка живая будет 7 дней.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2428
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 30.01.17 21:52. Заголовок: evbut пишет: И вот..


evbut пишет:

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


Проблема кода в том, что решение о регистрации паттерна разбросано по нескольким независимым функциям. Так, в основной функции FillPatternsDB несколько раз производятся одни и те же действия.
Сначала определяется направление паттерна:

 цитата:
ENUM_PATTERN_TYPE newPattern = PatternDir(index);


Сразу заметим, что функция PatternDir() вызывает функции IsBullsRailsPattern(), IsBUOVBPattern(), IsBullsPPRPattern() и IsBullsWRBPattern(). Причем этот вызов никак не реагирует на значения настроечных параметров, определяющих, какой паттерн следует искать. Как бы мы не настраивали индикатор, все равно он будет искать все включенные в него паттерны. Уже просчет.

Возвращаемся в FillPatternsDB(). Следующая строка:

 цитата:
ENUM_PATTEN_NAME newPatternName = NamePattern(index);


определяет имя паттерна. Как это делается? Снова через вызов функций IsBullsRailsPattern(), IsBUOVBPattern(), IsBullsPPRPattern() и IsBullsWRBPattern(). Но ведь мы вызывали эти функции для бара index! То есть снова выполняется уже проделанная работа.
Если идти далее, то видим третью строку FillPatternsDB():

 цитата:
int startBar = GetStartBar(index);


Причем функция GetStartBar() вновь оперирует теми же самыми функциями: IsBullsRailsPattern(), IsBUOVBPattern(), IsBullsPPRPattern() и IsBullsWRBPattern(). То есть эти функции были вызваны три раза на одном и том же баре.
Но и это еще не беда. Беда в том, что функции вызываются каждый раз в разном порядке:
    1. В PatternDir() порядок такой: Рельсы, OVB, PPR, WRB.
    2. В NamePattern: Рельсы, OVB, PPR, WRB.
    3. В GetStartBar: PPR, WRB, OVB, Рельсы.

В итоге получается каша. Если на одном и том же баре имеется несколько разных паттернов, то имя и направление берется от одного паттерна, а номер стартового бара - от другого.

Вывод. Таким образом, по озвученной проблеме рецепт такой: во всех функциях сделать единый порядок проверки паттернов, чтобы не было расхождений в регистрации.

По всему коду вывод другой: сделать централизованную регистрацию паттернов, без необходимости поиска паттернов на одном баре несколько раз. То есть, вызвав условную функцию ЕстьЛиПаттернНаЭтомБаре(), нужно сразу получить и тип паттерна, и его направление, и стартовый бар. Именно в этой функции следует разместить проверки значений настроечных параметров, указывающих, какой паттерн следует искать, а какой - нет. Это значительно ускорит работу индикатора. Кроме того нужно заранее продумать приоритеты паттернов. В тех случаях, когда на одном баре возникает сразу несколько паттернов и все они подлежат отображению, то из найденных следует выбрать только один паттерн, с наибольшим приоритетом.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 61
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 31.01.17 15:09. Заголовок: Scriptong пишет: сд..


Scriptong пишет:

 цитата:
сделать централизованную регистрацию паттернов, без необходимости поиска паттернов на одном баре несколько раз.



 цитата:
Это значительно ускорит работу индикатора


В целом омтечается заторможенность работы индикатора в этом виде кода, особенно когда историю большую ставишь... Если я правильно понял, стоит вернуть ваши функции FindAndShow-бла-блаPattern, что позволит ускорить его работу... Или будет достаточно расширить функционал функции FillPatternDB?


 цитата:
В тех случаях, когда на одном баре возникает сразу несколько паттернов и все они подлежат отображению, то из найденных следует выбрать только один паттерн, с наибольшим приоритетом.


Не совсем понимаю как задать приоритет паттернов программно. Переменная указанная ниже не решает этот вопрос?

 цитата:
enum ENUM_PATTEN_NAME
{
NONE_INDEX =-1,
RAILS_,
OVB_,
PPR_,
WRB_
};




Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2434
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 31.01.17 21:07. Заголовок: evbut пишет: Или бу..


evbut пишет:

 цитата:
Или будет достаточно расширить функционал функции FillPatternDB


Нужно сделать так, чтобы на одном и том же баре не повторялись одни и те же действия. То есть вместо нескольких отдельных вызовов разных функций (PatternDir(), NamePattern(), GetStartBar()) нужно сделать одну функцию, которая все это вычисляет. Ведь все равно задача каждой из этих функций сводится к вызову одних и тех же функций. В итоге вместо трех вызовов функций IsBullsRailsPattern(), IsBUOVBPattern(), IsBullsPPRPattern() и IsBullsWRBPattern() будет лишь один их вызов.
Кстати, далее по коду FillPatternsDB() следует еще один вызов PatternDir(). Для чего? Ведь результат ее вызова уже кеширован в переменной newPattern. Вообще это очень плохая практика - прибегать к вызову одной и той же функции в прилежащих кусках кода. Ведь в этом случае Вы делаете упор на то, что результат вычислений функции будет один и тот же. Но это бывает далеко не всегда. К примеру, имеется такая распространенная ошибка у программистов, которая приводит к получению фатальной ошибки zero divide:

 цитата:
if (AccountEquity() != 0.0)
fPercent = fProfit / AccountEquity()


Здесь, казалось бы, перед операцией деления имеется проверка результата функции на равенство нулю. Но между двумя вызовами этой функции проходит время (пусть небольшое). За этот период времени значение, возвращаемое AccountEquity(), может измениться и стать равным нулю. Правильный подход в данном случае такой:

 цитата:
double fEquity = AccountEquity();
if (fEquity != 0.0)
fPercent = fProfit / fEquity



evbut пишет:

 цитата:
Не совсем понимаю как задать приоритет паттернов программно.


Сделать везде одинаковый порядок вызова функций, определяющих наличие паттерна. Паттерн, обрабатываемый первым, получит наивысший приоритет.



Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 62
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 01.02.17 02:28. Заголовок: Scriptong пишет: То..


Scriptong пишет:

 цитата:
То есть вместо нескольких отдельных вызовов разных функций (PatternDir(), NamePattern(), GetStartBar()) нужно сделать одну функцию, которая все это вычисляет.


Не знаю насколько оптимальное решение, но все эти функции вывел в FillPatternsDB (переименовал ее трохи)
Скрытый текст


 цитата:
Сделать везде одинаковый порядок вызова функций, определяющих наличие паттерна. Паттерн, обрабатываемый первым, получит наивысший приоритет.


И с порядком теперь получается порядок )) По поводу перекрытости паттернов ломаю голову дальше в плане установления приоритетности паттернов... Ведь нигде в коде не обозначено, что последовательность имен паттернов в enum ENUM_PATTEN_NAME

 цитата:
enum ENUM_PATTEN_NAME
{
NONE_INDEX =-1,
RAILS_,
OVB_,
WRB_,
PPR_

};


задает приоритет PPR над всеми остальными. Или только в совокупности расположения в ENUM_PATTEN_NAME и такой же последовательности вызова функций определяет приоритет? Этот момент не укладывается в голове ))
Еще такой момент: необходимо снизить нагрузку на компьютер. Найденное большое количество паттернов записанное в массив нагружает систему... а если много пар в работе - зависон полный будет. Решение проблемы пока такое вижу - запись параметров найденных и неперекрытых паттернов в файл, откуда функция ShowPatterns будет считывать исторические данные по символу и отрисовывать, а массив g_patterns - либо обнулять, либо пусть помнит не более 20-30 последних найденных паттернов, при деинициализации индикатора скидывал бы их в этот файл. Как по вашему рациональный подход или есть более оптимальный вариант, который мне пока в голову не приходит?

PS. Еще раз почитав код индикатора "Всплеск и полка" пришел к окончательному выводу - держать в памяти отработанные паттерны в принципе нет - они только нагружают ПК.. поэтому концовку представленной выше функции будет выглядеть так

 цитата:
//== и подадим сигнал
SignalOnPattern(g_patterns[patternArray], isAlert,index,lastAlert,soundpattern);
}
//== Если включен флаг "Не показывать перекрытые паттерны удалим лишние
if(!OverLaidPattern)
{
ProcessPatterns(index);
}
// == Раскрасим патерны и удалим отработанные из массива
for(int j = ArraySize(g_patterns)-1; j >= 0; j--)
{
ReDrawPattern(g_patterns[j]);
if(g_patterns[j].getTarget == WORKED)
DeleteElementFromArray(g_patterns, j);
}
}


А запись в файл полезно будет лишь в случае исследования паттернов на предмет факта отработки по имени паттерна, его направлению и сроку отработки (сколько времени прошло с момента формирования до момента отработки).

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2436
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 06.02.17 16:30. Заголовок: evbut пишет: Не зна..


evbut пишет:

 цитата:
Не знаю насколько оптимальное решение, но все эти функции вывел в FillPatternsDB (переименовал ее трохи)


Не самое плохое решение Можно и так. В итоге приоритет поиска паттернов в данном случае получается следующий:
    1. PPR (т. к. его поиск идет самым последним, а, значит, паттерн при нахождении затрет любой другой паттерн)
    2. WRB
    3. OVB
    4. Рельсы

Сразу возникает вопрос: если на одном баре было зарегистрировано сразу четыре разных паттерна (гипотетически), и нам заранее известно, что будет принят только PPR, то зачем производился поиск всех остальных паттернов?
Ответ на этот вопрос: не нужно так делать. Паттерн с наивысшим приоритетом должен разыскиваться первым. Если же этот паттерн найден, то к поиску других паттернов даже приступать не стоит:

 цитата:
if(IsShowPPRPattern)
{
if(IsBullsPPRPattern(index))
{
newPattern = BULL_TYPE;
newPatternName = PPR_;
startBar = index + 2;
}
if(IsBearsPPRPattern(index))
{
newPattern = BEAR_TYPE;
newPatternName = PPR_;
startBar = index + 2;
}
}

if(IsShowSourcePattern && newPatternName == NONE_INDEX)
{
if(IsBullsWRBPattern(index))
{
newPattern = BULL_TYPE;
newPatternName = WRB_;
startBar = index + 2;
}
if(IsBearWRBPattern(index))
{
newPattern = BEAR_TYPE;
newPatternName = WRB_;
startBar = index + 2;
}
}

if(IsShowOVBPattern && newPatternName == NONE_INDEX)
{
if(IsBUOVBPattern(index))
{
newPattern = BULL_TYPE;
newPatternName = OVB_;
startBar = index + 1;
}

if(IsBEOVBPattern(index))
{
newPattern = BEAR_TYPE;
newPatternName = OVB_;
startBar = index + 1;
}
}

if(IsShowRailsPattern && newPatternName == NONE_INDEX)
{
if(IsBullsRailsPattern(index))
{
newPattern = BULL_TYPE;
newPatternName = RAILS_;
startBar = index + 1;
}
if(IsBearsRailsPattern(index))
{
newPattern = BEAR_TYPE;
newPatternName = RAILS_;
startBar = index + 1;
}
}




Спасибо: 1 
ПрофильЦитата Ответить





Сообщение: 2437
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 06.02.17 16:32. Заголовок: evbut пишет: И с по..


evbut пишет:

 цитата:
И с порядком теперь получается порядок )) По поводу перекрытости паттернов ломаю голову дальше в плане установления приоритетности паттернов... Ведь нигде в коде не обозначено, что последовательность имен паттернов в enum ENUM_PATTEN_NAME


Приоритеты поиска паттернов не зависят от последовательности объявления паттернов в перечислении. Приоритет назначается программно. Как именно - показал постом выше.

Спасибо: 1 
ПрофильЦитата Ответить





Сообщение: 2438
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 06.02.17 16:36. Заголовок: evbut пишет: Еще та..


evbut пишет:

 цитата:
Еще такой момент: необходимо снизить нагрузку на компьютер. Найденное большое количество паттернов записанное в массив нагружает систему... а если много пар в работе - зависон полный будет. Решение проблемы пока такое вижу - запись параметров найденных и неперекрытых паттернов в файл, откуда функция ShowPatterns будет считывать исторические данные по символу и отрисовывать, а массив g_patterns - либо обнулять, либо пусть помнит не более 20-30 последних найденных паттернов, при деинициализации индикатора скидывал бы их в этот файл. Как по вашему рациональный подход или есть более оптимальный вариант, который мне пока в голову не приходит?


Так, для справки: файловые операции, даже на SSD-диске многократно уступают по скорости в сравнении с оперативной памятью. Именно поэтому все программы для совей работы записывают данные в оперативную память, а не в файл. В файлы данные пишутся для хранения, пока программа не работает.
Проблема большой нагрузки в данном случае не в том, что происходит работа с памятью, а в том, что программа занимается лишней работой. Так, посмотрев работу программы в профилировщике, сразу видим корень зла:

Это функция IsPatternWorked(). В ней каждый паттерн на каждом новом баре проверяется на предмет отработки (достижения цели). Более того, на каждом баре функция вызывается дважды: в FindPatternsAndFillDB() и в ReDrawPattern().
Лишняя работа заключается в том, что сразу при обнаружении паттерна производится проход по все истории от момента возникновения паттерна до текущего момента времени. Зачем? Ведь у нас уже имеется цикл, идущий по истории (в ShowIndicatorData()). Пусть он и задает текущий бар, на котором нужно проверять отработку паттерна. При таком подходе в IsPatternWorked исчезнет цикл, что сразу решит проблему быстродействия.

Спасибо: 1 
ПрофильЦитата Ответить
постоянный участник




Сообщение: 2496
Зарегистрирован: 04.03.13
Откуда: Москва
Репутация: 3
ссылка на сообщение  Отправлено: 05.02.17 09:50. Заголовок: Встретился мне на за..


Встретился мне на забугорном форуме http://www.for-exe.com/mt4-free-indicators--scripts.html индикатор snorm_multibar_pinbar с
подобной реализацией идеи отображением паттернов, но только для Пин-бара.



С уважением! Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 64
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 07.02.17 06:18. Заголовок: Так, развейте не сты..


Так, развейте не стыковку по вашим высказываниям. Порядок приоритетности я брал из статьи по индикатору "Простые паттерны" (и в нем же порядок поиска паттернов располагается по возрастающему, с ваших слов в статье, приоритету - от "Inside Bar" до Island Reversal) и здесь
Scriptong пишет:

 цитата:
1. PPR (т. к. его поиск идет самым последним, а, значит, паттерн при нахождении затрет любой другой паттерн)


И далее по тексту читаю
Scriptong пишет:

 цитата:
Паттерн с наивысшим приоритетом должен разыскиваться первым.

.
Так как же на самом деле правильно?

Лирическое отступление )))
Логически как бы понятно, что чем реже встречается паттерн, тем сильнее он. Среди двух баровых - "Поглащение" будет сильней Рельс. Среди трех баровых из моего списка наверно предпочтение нужно отдать WRB... Но тот же PPR чаще встречается, чем теже Рельсы или Поглащение... И думается мне, что приоритетность на одном баре нужно определять как в поговорке "Кто первый встал, того и тапки"

Использование такого подхода получается частично избавляет от необходимости удалять перекрытые паттерны. А пока что не могу избавиться от функции

 цитата:

ENUM_PATTEN_NAME NamePattern(int index)
{
if(IsBullsPPRPattern(index) || IsBearsPPRPattern(index))
return PPR_;
if(IsBullsWRBPattern(index) || IsBearWRBPattern(index))
return WRB_;
if(IsBUOVBPattern(index) || IsBEOVBPattern(index))
return OVB_;
if(IsBullsRailsPattern(index) || IsBearsRailsPattern(index))
return RAILS_;
return NONE_INDEX;
}


Чтобы реализовать удаление перекрытых... Как говориться: "в голове вертится, а на язык не идет"... т.е. понимаю, что функционал удаления, можно воткнуть также в функцию FindPatternsAndFillDB на этапе нахождения минимум первых 3ёх любых паттернов, чтобы просто не давать накладывающимся паттернам записываться в БД согласно их приоритету.

Спасибо за наводку с профилированием - теперь знаю для чего нужна эта кнопочка )))

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2441
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 17.02.17 12:00. Заголовок: evbut пишет: Так, р..


evbut пишет:

 цитата:
Так, развейте не стыковку по вашим высказываниям. Порядок приоритетности я брал из статьи по индикатору "Простые паттерны" (и в нем же порядок поиска паттернов располагается по возрастающему, с ваших слов в статье, приоритету - от "Inside Bar" до Island Reversal) и здесь


Все зависит от логики программы. Можно построить логику так, что, найдя паттерн, будет произведен выход из функции поиска. На мой взгляд, это наиболее приемлемый вариант, т. к. отсекаются лишние действия.
В предложенном Вами варианте структура функции создана иначе (наоборот): так, что происходит поиск всех паттернов подряд и запись результата поиска в одну и ту же переменную. Поэтому логично, что паттерн, поиск которого следует последним, затрет информацию о всех ранее найденных паттернах.

Таким образом, по хорошему, функцию FindPatternsAndFillDB нужно разбить на несколько более мелких функций, сделав поиск паттерна с наивысшим приоритетом первым. Если паттерн найден, то остальные даже не разыскиваются. А вот если паттерн не найден, то происходит переход к поиску следующего паттерна.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 67
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 20.02.17 07:34. Заголовок: Scriptong пишет: Та..


Scriptong пишет:

 цитата:
Таким образом, по хорошему, функцию FindPatternsAndFillDB нужно разбить на несколько более мелких функций, сделав поиск паттерна с наивысшим приоритетом первым. Если паттерн найден, то остальные даже не разыскиваются. А вот если паттерн не найден, то происходит переход к поиску следующего паттерна.


Функцию на мелкие не стал разбивать - но предложенный вами вариант

 цитата:
f(IsShowPPRPattern && newPatternName == NONE_INDEX)


позволил сократить число обращение функций ккаждому бару, Так теперь поиск самого важного паттерна WRB происходит на 1000 барах, поиск PPR происходит уже на 949 барах, а паттерн рельсы вообще ищется только 783 барах.
И кстати говоря, функцию IsPatternWorked маленько модифицировал, но суть осталась прежней и она таки не тормазит индикатор теперь, а число обращений к ней составляет общему числу найденных паттернов, в текущем случае - 303 раза.


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2446
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 23.02.17 21:55. Заголовок: evbut пишет: И кста..


evbut пишет:

 цитата:
И кстати говоря, функцию IsPatternWorked маленько модифицировал, но суть осталась прежней и она таки не тормазит индикатор теперь, а число обращений к ней составляет общему числу найденных паттернов, в текущем случае - 303 раза.


Вы убрали цикл из этой функции? Если цикл убрать, то индикатор будет "летать"

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 65
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 12.02.17 12:13. Заголовок: Это функция IsPatter..



 цитата:
Это функция IsPatternWorked().


Познакомился с профилированием..Двойной вызов этой функции убрал. Вызовов самой функции сейчас на 1000 баров истории составляет 278, что соответствует количеству найденных паттернов. Однако вызовов iLow в ней 20650, хотя iHigh из нее же - 4951. Откуда такая разница в вызове этих строк, ведь они выполняют похожие действия и баров одинаковое количество проверяют? По логике их должно быть максимум 278 каждая...


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2442
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 17.02.17 12:23. Заголовок: evbut пишет: Откуда..


evbut пишет:

 цитата:
Откуда такая разница в вызове этих строк, ведь они выполняют похожие действия и баров одинаковое количество проверяют? По логике их должно быть максимум 278 каждая...


Дело то не столько в двойном вызове функции, а в том, что она делает огромное количество повторяющихся действий.
Разберем по полочкам, что же происходит.
1. Цикл i в ShowIndicatorData указывает на бар с индексом 1000. Допустим, на этом баре найден какой-то паттерн. В итоге вызывается функция IsPatternWorked(), которая запускает свой цикл от бара 1000 до бара с индексом 0. Получаем 1000 итераций сходу.
2. Цикл i в ShowIndicatorData указывает на бар с индексом 998. Допустим, на этом баре найден еще какой-то паттерн. Уже два паттерна. В итоге два раза вызывается функция IsPatternWorked(), которая запускает цикл от бара 998 до бара с индексом 0. Получаем 1996 итераций. Причем заметьте, что цикл для предыдущего найденного паттерна повторяет 998 итераций, которые были совершены на итерации цикла i = 1000 в ShowIndicatorData.
3. Цикл i в ShowIndicatorData указывает на бар с индексом 995. Допустим, на этом баре найден еще какой-то паттерн. Уже три паттерна. В итоге три раза вызывается функция IsPatternWorked(), которая запускает цикл от бара 995 до бара с индексом 0. Получаем 2985 итераций. Здесь уже два цикла лишних, т. к. эта работа уже давно выполнена.
4. Цикл i в ShowIndicatorData указывает на бар с индексом 500. Допустим, к этому моменту найдено 100 паттернов. В итоге 100 раз вызывается функция IsPatternWorked(), которая запускает цикл от бара 500 до бара с индексом 0. Получаем 500 * 100 = 50 000 итераций.

В итоге за 500 обработанных баров было совершено огромное количество лишней работы, которая и приводит к такому медленному выполнению индикатора. Чтобы уйти от такой неоптимальности, в функции IsPatternWorked() нужно избавиться от циклов. Они не нужны. Достаточно проверить отработку каждого найденного на данный момент паттерна на текущем баре (тот, который в цикле i ShowIndicatorData).

P. S. Ну а разность вызовов iLow и iHigh объясняется просто: они ведь вызываются в зависимости от типа паттерна.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 66
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 13.02.17 10:51. Заголовок: Игорь, здравствуйте!..


Игорь, здравствуйте! Появилось желание сделать индикатор под МТ5. Судя по ошибкам, выдаваемым компилятором МТ5 главная загвоздка будет состоять в переделке в функциях нахождения паттернов, а именно всякие Low, High, Close и подобные, которых в mql5 нету... Универсальности кода по-видимому не получиться... Нужно искать аналоги... На что еще стоит обратить внимание в испытуемом коде при переносе в mql5 для корректной работы?

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2443
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 17.02.17 12:25. Заголовок: evbut пишет: Игорь,..


evbut пишет:

 цитата:
Игорь, здравствуйте! Появилось желание сделать индикатор под МТ5. Судя по ошибкам, выдаваемым компилятором МТ5 главная загвоздка будет состоять в переделке в функциях нахождения паттернов, а именно всякие Low, High, Close и подобные, которых в mql5 нету... Универсальности кода по-видимому не получиться... Нужно искать аналоги... На что еще стоит обратить внимание в испытуемом коде при переносе в mql5 для корректной работы?


Чтобы переходить на МТ5, сначала следует полностью отладить программу на МТ4. Без этого никак. Ну а универсальность кода для индикаторов вполне достижима (для советников - нет). Чтобы написать в стиле МТ5, используйте функции типа Copy (CopyRates, CopyHigh, CopyLow и т. д.) вместо iLow, iHigh И т. д. Правда придется немного поменять подход к их использованию, готовя данные заранее, а не беря их в том месте, где потребовались.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 68
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 24.02.17 01:50. Заголовок: Вы убрали цикл из эт..



 цитата:
Вы убрали цикл из этой функции?


Нет... с цикломосталось, но через свич

 цитата:
ENUM_GET_TARGET IsPatternWorked(Pattern &pattern)
{
for(int k = iBarShift(NULL,0,pattern.rightTime); k > 0; k--)
{
switch(pattern.patternType)
{
case BULL_TYPE : if(iHigh(NULL,0,k) > pattern.patternTarget)
return pattern.getTarget = WORKED; break;

case BEAR_TYPE : if(iLow(NULL,0,k) < pattern.patternTarget)
return pattern.getTarget = WORKED; break;
}
}
return (g_patterns[ArraySize(g_patterns)-1].getTarget);
}



Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2448
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 02.03.17 14:31. Заголовок: evbut пишет: Нет.....


evbut пишет:

 цитата:
Нет... с цикломосталось, но через свич


Настоятельно рекомендую сделать так:

 цитата:
ENUM_GET_TARGET IsPatternWorked(Pattern &pattern, int nBarIndex)
{
if (pattern.getTarget == WORKED)
return pattern.getTarget;

switch(pattern.patternType)
{
case BULL_TYPE : if (iHigh(NULL,0,nBarIndex) > pattern.patternTarget)
pattern.getTarget = WORKED;
break;

case BEAR_TYPE : if(iLow(NULL,0,nBarIndex) < pattern.patternTarget)
pattern.getTarget = WORKED;
break;
}
return (pattern.getTarget);
}



Не проверял синтаксис, могут быть ошибки. В целом смысл такой: передавать в функцию IsPatternWorked индекс обрабатываемого бара. И только на нем проверять отработку паттерна. Не нужно на каждом баре проверять отработку паттерна от момента его регистрации до нулевого бара. Это огромное количество лишней работы. Итогом станет многократный рост производительности индикатора.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 69
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 03.03.17 11:06. Заголовок: Настоятельно рекомен..



 цитата:
Настоятельно рекомендую сделать так:


Не работает так с имеющимся кодом - еще на начальном этапе ее конструирования она ничего не делала - как были паттерны ACTUAL, так и остаются, поскольку эта функция передает свой результат в функцию FindPatternsAndFillDB (int index)

 цитата:
g_patterns[patternArray].getTarget =
(IsPatternWorked(g_patterns[patternArray],index) == WORKED)? WORKED : ACTUAL;



Откуда должен передаваться индекс обрабатываемого бара?


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2452
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 03.03.17 18:13. Заголовок: evbut пишет: Не раб..


evbut пишет:

 цитата:
Не работает так с имеющимся кодом


Тогда нужен весь имеющийся код. Понятно, что проблема комплексная. Но, имея лишь фрагменты кода, я не смогу помочь с решением.

evbut пишет:

 цитата:
Откуда должен передаваться индекс обрабатываемого бара?


Из функции ShowIndicatorData.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 70
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 05.03.17 02:16. Заголовок: ЗДЕСЬ 14 Дней будет ..


ЗДЕСЬ 14 Дней будет лежать Крайняя версия индикатора. В ней мал-мало переделал функцию неотображения перекрывающихся паттернов, добавил опцию удаления отработанных, а также добавил еще один паттерн - Fakey.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2456
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 23.03.17 16:36. Заголовок: evbut пишет: ЗДЕСЬ ..


evbut пишет:

 цитата:
ЗДЕСЬ 14 Дней будет лежать Крайняя версия индикатора. В ней мал-мало переделал функцию неотображения перекрывающихся паттернов, добавил опцию удаления отработанных, а также добавил еще один паттерн - Fakey.


К сожалению, меня не было здесь больше - был в отпуске. Повторите, пожалуйста.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 71
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 23.03.17 18:43. Заголовок: С возвращением в сур..


С возвращением в суровые будни )) Надеюсь отпуск удался?
Пожалуйста




Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2460
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 24.03.17 15:42. Заголовок: evbut пишет: С возв..


evbut пишет:

 цитата:
С возвращением в суровые будни )) Надеюсь отпуск удался?
Пожалуйста


Скачал. Чуть позже гляну.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2462
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 28.03.17 14:39. Заголовок: evbut пишет: С возв..


evbut пишет:

 цитата:
С возвращением в суровые будни )) Надеюсь отпуск удался?
Пожалуйста


Уже намного выше быстродействие, чем было. Внес несколько правок.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 72
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 27.03.17 07:40. Заголовок: На перспективу появи..


На перспективу появилось жгучее желание сделать из него мульти кросплатформенную (MT4/MT5) версию, чтоб на желаемых инструментах из списка и на любых ТФ искал паттерны, а потом отображал в виде таблицы на подобии Этой Панели. Эх, жалко что нет исходника этой панельки - так бы можно было бы пошаманить... А поскольку там уже классы используются, то задумку придется отложить в долгий ящик, пока не пойму что это такое - классы ... Со структурой то еще шибко храмают навыки... А тут классы - дремучий лес )))
А вообще, как вы считаете будет ли достаточным в структуру struct Pattern просто добавить такие переменные как patternSymbol и patternTimeFrame, что бы бы сделать его по моему желанию? Или можно обойтись вообще без структуры -получать данные из функций типа IsBullsRailsPattern, IsBearsRailsPattern и т.д? Ведь по большому счету нужен будет лишь факт нахождения на конкретном символе, конкретного ТФ на первом баре конкретного паттерна и его таргета...


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2463
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 28.03.17 14:43. Заголовок: evbut пишет: Эх, жа..


evbut пишет:

 цитата:
Эх, жалко что нет исходника этой панельки - так бы можно было бы пошаманить...


У меня имеется подобная, правда не в подокне, а в основном окне. Делалось для поиска дивергенций на разных символах/периодах - Сканер дивергенций.

Спасибо: 1 
ПрофильЦитата Ответить





Сообщение: 2464
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 28.03.17 14:47. Заголовок: evbut пишет: А вооб..


evbut пишет:

 цитата:
А вообще, как вы считаете будет ли достаточным в структуру struct Pattern просто добавить такие переменные как patternSymbol и patternTimeFrame, что бы бы сделать его по моему желанию? Или можно обойтись вообще без структуры -получать данные из функций типа IsBullsRailsPattern, IsBearsRailsPattern и т.д? Ведь по большому счету нужен будет лишь факт нахождения на конкретном символе, конкретного ТФ на первом баре конкретного паттерна и его таргета...


Есть разные пути для внедрения мультимивола/мультипериода. Можно обойтись и без классов/структур в процедурном стиле. Но элегантнее код будет выглядеть для таких случаев именно в ООП. Соответственно, его отладка станет намного проще процедурного подхода.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 76
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 29.03.17 07:05. Заголовок: Гран мерси. Теперь м..


Гран мерси. Теперь можно и за кросс-платформенный вариант приниматься ))) а уж потом мастрить мульти-пульти версию

 цитата:
Чтобы написать в стиле МТ5, используйте функции типа Copy (CopyRates, CopyHigh, CopyLow и т. д.) вместо iLow, iHigh И т. д. Правда придется немного поменять подход к их использованию, готовя данные заранее, а не беря их в том месте, где потребовались.


Тут наверно лучше использоваться CopyRates, вместо 4 других Copy... А вот в OnCalculate есть уже массивы: high, low и проч... Их Никак нельзя использовать?

PS. Попробовал прикрутить MqlRates rates[]. Прописал ее в глобальных переменных. В int GetRecalcIndex добавил строку ArrayResize(rates,0.0) - типа обнулять массив при смене таймфрейма. Затем в ShowIndicatorData прописал

 цитата:
for (int i = limit; i > 0; i--)
{
int copied = CopyRates(NULL,0,0,i,rates);
Print(copied);
if (!FindPatternsAndFillDB(i))
return false;


Принт мне перечислил значения copied от 210 до 1. Но когда в OnCalculate

 цитата:
int limit = GetRecalcIndex(total, rates_total, prev_calculated); //GetRecalcIndex(total);
int copied = CopyRates(NULL,0,0,total,rates);
Print(copied);


Принт выдает 1000. Именно такое по умолчанию стоит значение indBarsCount.
Почему так? Ну и разумеется при замене Low на rates[index].low вылазит ошибка выхода за пределы массива (( Чот видать не туда шагать начал ((

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2466
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 29.03.17 20:04. Заголовок: evbut пишет: Тут на..


evbut пишет:

 цитата:
Тут наверно лучше использоваться CopyRates, вместо 4 других Copy...


Это зависит от того, какого рода информация нужна. Бывает так, что информация по всей свече не требуется.

evbut пишет:

 цитата:
А вот в OnCalculate есть уже массивы: high, low и проч...


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

evbut пишет:

 цитата:
Принт мне перечислил значения copied от 210 до 1. Но когда в OnCalculate


Если смотрели в журнале, который в закладке "Эксперты", то вполне такое может быть. Этот журнал при массовом выводе информации режет ее, чтобы не было переполнения. В таких случаях журнал нужно смотреть через контекстное меню закладки логов "Открыть". Если открыть полную версию журнала, то получим те же 1000 значений.

evbut пишет:

 цитата:
Ну и разумеется при замене Low на rates[index].low вылазит ошибка выхода за пределы массива (( Чот видать не туда шагать начал ((


Имейте в виду, что нумерация баров после использования функций типа Copy изменяется на противоположную. Причем в достаточно сложном сочетании, т. к. нулевой элемент всякий раз указывает на разный бар. С этим фактом всегда ломается огромное количество копий.



Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 77
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 29.03.17 23:53. Заголовок: Scriptong пишет: Им..


Scriptong пишет:

 цитата:
Имейте в виду, что нумерация баров после использования функций типа Copy изменяется на противоположную. Причем в достаточно сложном сочетании, т. к. нулевой элемент всякий раз указывает на разный бар. С этим фактом всегда ломается огромное количество копий.


ArraySetAsSeries(rates,true) не помогает в этом случае? И как обычно борются с этой напастью?

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2468
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 03.04.17 19:42. Заголовок: evbut пишет: ArrayS..


evbut пишет:

 цитата:
ArraySetAsSeries(rates,true) не помогает в этом случае? И как обычно борются с этой напастью?


Не советую. И не напасть это, а обычная работа с данными. Просто привыкнуть нужно и научиться ориентироваться в получаемых массивах.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 78
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 30.03.17 09:34. Заголовок: Решил проблему. Не з..


Решил проблему. Не знаю на сколько оправдано, тем не менее работает и в МТ4 и в МТ5.
CopyRates(NULL,0,0,rates_total,rates)

Можно приниматься за мультивсяковость ))




Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2469
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 03.04.17 20:00. Заголовок: evbut пишет: Решил ..


evbut пишет:

 цитата:
Решил проблему. Не знаю на сколько оправдано, тем не менее работает и в МТ4 и в МТ5.
CopyRates(NULL,0,0,rates_total,rates)


Не-не, очень плохо. Зачем Вам весь массив данных, если максимум четыре бара для поиска паттерна требуется? Просто на каждом баре запрашивайте четыре последних свечи:

 цитата:
MqlRates stRates[];
if (CopyRates(Symbol(), PERIOD_CURRENT, nBarIndex, 4, stRates) < 0)
{
// ошибка
return;
}


Имеется в виду, что nBarIndex - это текущий обрабатываемый бар (тот, который в главном цикле задается). От него, включая его, запрашивается всего 4 бара. Это достаточно быстрая операция. Если выполнение функции успешно завершено, то в элементе 0 массива stRates будут данные о баре (nBarIndex + 3), в элементе 1 - данные от (nBarIndex + 2), в элементе 2 - данные (nBarIndex + 1) и в элементе 3 - от бара nBarIndex.

P. S. Кстати, в MQL5 конструкция CopyRates(NULL, 0...) работать не будет. Обязательно требуется CopyRates(Symbol(), PERIOD_CURRENT...).

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 79
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 04.04.17 14:00. Заголовок: Scriptong пишет: Кс..


Scriptong пишет:

 цитата:
Не советую. И не напасть это, а обычная работа с данными.


Без ArraySetAsSeries не отображаются паттерны, а с ним отображаются

 цитата:
Кстати, в MQL5 конструкция CopyRates(NULL, 0...) работать не будет.


Хм... а ведь работает

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2470
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 04.04.17 20:54. Заголовок: evbut пишет: Без Ar..


evbut пишет:

 цитата:
Без ArraySetAsSeries не отображаются паттерны, а с ним отображаются


Я же говорю - массив переворачивается. А ArraySetAsSeries переворачивает его обратно, в таймсерию. Если не хочется переписывать функции поиска паттернов, то да, нужен ArraySetAsSeries. Но в этом случае код получается не адаптированным, а именно переведенным (как Google Translate переводит с одного языка на другой) на MQL5. То есть по-хорошему для универсального кода нужно переписать функции поиска паттернов, развернув в них нумерацию баров.

evbut пишет:

 цитата:

Хм... а ведь работает


Сейчас работает, но нет гарантий, что будет работать в будущем. Это недокументированная возможность, перешедшая с MQL4. Поменяют MetaQuotes значения перечислений, и тогда все подобные коды полетят в тартарары.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 80
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 05.04.17 02:58. Заголовок: Scriptong пишет: То..


Scriptong пишет:

 цитата:
То есть по-хорошему для универсального кода нужно переписать функции поиска паттернов, развернув в них нумерацию баров.


Ну да... поглядел несколько кодов на MQL5 и в них наоборот пишется, т.е. если в MQL4 пишем к примеру

 цитата:
if(Close[index] >= Low[index+1]) // Минимум предыдущей свечи не пробит
return(false);


то в MQL5 это будет кажется вот так

 цитата:
if(Close[index-1] >= Low[index]) // Минимум предыдущей свечи не пробит
return(false);



Поразмыслил над вашим

 цитата:
что nBarIndex - это текущий обрабатываемый бар (тот, который в главном цикле задается). От него, включая его, запрашивается всего 4 бара. Это достаточно быстрая операция. Если выполнение функции успешно завершено, то в элементе 0 массива stRates будут данные о баре (nBarIndex + 3), в элементе 1 - данные от (nBarIndex + 2), в элементе 2 - данные (nBarIndex + 1) и в элементе 3 - от бара nBarIndex.


и получается, что на каждом новом баре бар nBarIndex + 3 будет запрашиваться 1 раз, бар nBarIndex + 2 - два раза и nBarIndex + 1 - три раза... как вы говорите двойная работа и даже тройная... Или нет? Такое необходимо только 1 раз сделать при первом обращении в функцию OnCalculate, а далее записывать в массив MQLrates данные только первого бара.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2472
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 07.04.17 20:24. Заголовок: evbut пишет: то в M..


evbut пишет:

 цитата:
то в MQL5 это будет кажется вот так


Ни в коем случае. В MQL5 другой подход к сбору данных: через функции CopyXXX. Такой же способ сбора данных имеется в MQL4. Это и дает возможность написания кроссплатформенных кодов. То есть даже в MQL4 при использовании способа получения данных через CopyXXX придется разворачивать логику.

evbut пишет:

 цитата:
и получается, что на каждом новом баре бар nBarIndex + 3 будет запрашиваться 1 раз, бар nBarIndex + 2 - два раза и nBarIndex + 1 - три раза... как вы говорите двойная работа и даже тройная... Или нет? Такое необходимо только 1 раз сделать при первом обращении в функцию OnCalculate, а далее записывать в массив MQLrates данные только первого бара.


Для чего тянуть весь массив данных (если пополнять MQLRates)? Это не нужно, т. к. потребует лишнюю память. Просто на каждой итерации запрашиваются данные о 4 барах и к следующей итерации они благополучно теряются. Ведь все равно на каждой итерации необходимо делать запрос данных, хотя бы одного (нового) бара. А 1 бар будет запрошен или 4 бара - разницы практически никакой. Другое дело, если бы речь шла о тысячах баров. Тогда нужно было бы что-то придумывать.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 81
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 08.04.17 13:37. Заголовок: То есть даже в MQL4 ..



 цитата:
То есть даже в MQL4 при использовании способа получения данных через CopyXXX придется разворачивать логику.


Покумекал в общем и вот что на мой взгляд подойдет кроссплаформенности:
Создадим еще одну структуру "Candle",

 цитата:
struct Candle
{
ENUM_BARTYPE type;
double open,high,low,close, body, shadow, height;
datetime time; //Время
Candle()
{
Init();
}
void Init()
{
type = NONE_BAR;
open = 0.0;
close = 0.0;
high = 0.0;
low = 0.0;
body = 0.0;
shadow = 0.0;
height = 0.0;
time = -1;
}
};
Candle g_candles[]; //Свечи



которую заполним данными:

 цитата:
if(!CopyRates(symbol,period,time,4,rates))
return false;
for(int i = 0; i < 4; i++)
{
candle.close = rates.close;
candle.open = rates.open;
candle.high = rates.high;
candle.low = rates.low;
candle.time = rates.time;
candle.type = (rates.close < rates.open)? BEAR_BAR : BULL_BAR;
candle.shadow = (candle.type == BULL_BAR)?
MathMin(rates.open, rates.close) - rates.low :
rates.high - MathMax(rates.open, rates.close);

candle.height = rates.high - rates.low;
candle.body = MathAbs(rates.close - rates.open);
}


Ну и далее в каждой функции поиска паттерна через цикл for(int i = 0; i < ArraySize(g_candles); i++) исправляем всякие Close, High и Low и проч на данные из этой структуры
Не тот маршрут выбрал? )))

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2474
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 09.04.17 16:52. Заголовок: evbut пишет: Создад..


evbut пишет:

 цитата:
Создадим еще одну структуру "Candle",


Пока не понял преимущество такой надстройки. В моих кодах для таких целей пока хватало стандартной структуры MqlRates. То есть вместо того, чтобы использовать стандартные таймсерии, достаточно один раз на каждой итерации цикла запросить данные о последних 4-х барах и передать эту структуру всем функциям, которые используют данные для свечей.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 82
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 10.04.17 06:02. Заголовок: Это понятно, что коп..


Это понятно, что копировать на каждой i данные только 4х свечей включая саму i. Не поятен мне вопрос по смене логики, чтобы и в mql4и mql5 работало без ArraySetSeries.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2478
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 14.04.17 19:04. Заголовок: evbut пишет: Это по..


evbut пишет:

 цитата:
Это понятно, что копировать на каждой i данные только 4х свечей включая саму i. Не поятен мне вопрос по смене логики, чтобы и в mql4и mql5 работало без ArraySetSeries.


К примеру, в оригинальной версии поиск бычьего паттерна PPR выглядит так:

 цитата:
bool IsBullsPPRPattern(int index)
{
if(Close[index] <= High[index+1]) // Максимум предыдущей свечи не пробит
return(false); // Паттерн не сформирован

if (Low[index+1] >= Low[index+2] || // Минимум предыдущего бара не..
Low[index+1] >= Low[index]) // ..является минимумом паттерна
return(false); // Паттерн не сформирован

if (Close[index+2] >= Open[index+2]) // Стартовый бар паттерна не является
return(false); // ..медвежьим - выход*/

return(true); // Паттерн сформирован
}



Здесь index - бар, находящийся по графику правее, чем бар (index + 1).
Если же получен массив rates[4] при помощи CopyRates без использования ArraySetAsSeries, то функция будет выглядеть следующим образом:

 цитата:
bool IsBullsPPRPattern(const MqlRates &rates[4])
{
if (rates[3].close <= rates[2].high) // Максимум предыдущей свечи не пробит
return(false); // Паттерн не сформирован

if (rates[2].low >= rates[1].low || // Минимум предыдущего бара не..
rates[2].low >= rates[3].low) // ..является минимумом паттерна
return(false); // Паттерн не сформирован

if (rates[1].close >= rates[1].open) // Стартовый бар паттерна не является
return(false); // ..медвежьим - выход*/

return(true); // Паттерн сформирован
}



Здесь не используется элемент массива rates с индексом 0, т. к. это эквивалент бара (index + 3). Индекс 1 массива rates - это эквивалент бара (index + 2), элемент 2 - эквивалент (index + 1), а элемент 3 - эквивалент index. То есть все индексы "перевернуты".

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 83
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 15.04.17 15:59. Заголовок: Вот жеж... Взрыв моз..


Вот жеж... Взрыв мозга ))) Во времена первого знакомства с форекс именно так и считал, что нумерация баров начинается с более древней даты... Долго не мог вытравить из себя такой подход... За год наверно избавлися и приучил считать в виде таймсерий... а теперь придется снова приучать себя иногда именно так и считать бары))))
Функция поиска Внутреннего бара выглядела так:

 цитата:
bool IsIBPattern(int index, int total, int& patternStart)
{
while(IsSimpleIB(patternStart) && // Поиск элементарных паттернов подряд
patternStart < total)
patternStart++;

if (patternStart == index) // Ни один паттерн не найден
return(false);

return(true); // Паттерн найден
}


а теперь будет выглядеть вот так, если MqlRates rates[4] вынести на глобальный уровень?

 цитата:
bool IsIBPattern(int total, int& patternStart)
{
total = ArraySize(rates)-1;
for (int i = 0; i < total; i++)
{
while(IsSimpleIB() && // Поиск элементарных паттернов подряд
patternStart < total)
patternStart++;

if (patternStart == i) // Ни один паттерн не найден
return(false);
}
return(true); // Паттерн найден
}



А вообще не понятно зачем НЕ использовать ArraySetSeries? Пересмотрел кучу индикаторов в MQL5 и львиная доля её использует.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2480
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 20.04.17 16:18. Заголовок: evbut пишет: Вот же..


evbut пишет:

 цитата:
Вот жеж... Взрыв мозга ))) Во времена первого знакомства с форекс именно так и считал, что нумерация баров начинается с более древней даты... Долго не мог вытравить из себя такой подход... За год наверно избавлися и приучил считать в виде таймсерий... а теперь придется снова приучать себя иногда именно так и считать бары))))


На самом деле это очень полезно - уметь считать и так, и эдак. Избавляет мозг от узкого понимания ситуации и лишний раз напоминает ему, что все в этом мире относительно. Кстати, в трейдинге очень помогает

evbut пишет:

 цитата:
Функция поиска Внутреннего бара выглядела так:
а теперь будет выглядеть вот так, если MqlRates rates[4] вынести на глобальный уровень?


Точно не так, т. к. цикл i ничего не дает для функции IsSimpleIB(). Как ей узнать, что нужно обращаться к другим барам? Или же здесь цикл i лишний, а все изменения касаются именно функции IsSimpleIB().

evbut пишет:

 цитата:
А вообще не понятно зачем НЕ использовать ArraySetSeries? Пересмотрел кучу индикаторов в MQL5 и львиная доля её использует.


Львиная доля индикаторов, написанная на MQL, это очень низкий уровень написания кода. В этой сфере очень мало профессиональных программистов. Потому и подходы далеко не всегда верные. Хотя против ArraySetAsSeries() ничего не имею. Это как раз нельзя считать плохим тоном. То есть да, можно и при помощи ArraySetAsSeries работать, по старинке. Просто мне всегда казалось логичным нумеровать бары именно слева направо по истории, а не наоборот. Поэтому был рад, когда в MQL5 появилась такая нумерация. Ведь любой бар в истории отныне имеет неизменный индекс.

Спасибо: 0 
ПрофильЦитата Ответить



Сообщение: 84
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 19.04.17 09:40. Заголовок: Пытаюсь разобраться ..


Пытаюсь разобраться с прямой и обратной индексацией баров и CopyRates
Запрашиваю данные 4 свечей с принтом (limit = 20).

 цитата:
for (int i = limit; i > 0; i--)
{
ratesCnt = CopyRates(_Symbol,PERIOD_CURRENT,i,4,rates);
for(int j = ArraySize(rates)-1; j >=0; j--)
{
Print(j + " " + Time[j] + " High " + rates[j].high);
}


на картинке ценовые метки проставлены по хаям баром. Вертикальная линия стоит на баре = limit и видим, что дата его 22.032017. В принтах же нет такой даты по 4-м запрашиваемым барам ни с использованием ArraySetSeries ни без него. Почему так, я не правильно запросил время бара или это какое-то недоразумение со стороны какой-то функции?


Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2481
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 20.04.17 16:23. Заголовок: evbut пишет: Почему..


evbut пишет:

 цитата:
Почему так, я не правильно запросил время бара


Да, неправильно запросили время бара. Ведь Вы оперируете барами, записанными в массив rates, а не барами, записанными в таймсерию Time. Вместо:

 цитата:
Print(j + " " + Time[j] + " High " + rates[j].high);


нужно написать:

 цитата:
Print(j + " " + rates[j].time + " High " + rates[j].high);



Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 85
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 21.04.17 02:48. Заголовок: Scriptong пишет: ну..


Scriptong пишет:

 цитата:
нужно написать:


Аха... теперь затыка с границами паттернов, в частности с верхней и нижней в функции FindPatternsAndFillDB

 цитата:
double lowPrice = Low[iLowest(NULL,0,MODE_LOW,// Нижняя граница паттерна
startBar-endBar+1,endBar)];
double highPrice = High[iHighest(NULL,0,MODE_HIGH,// Верхняя граница паттерна
startBar-endBar+1,endBar)];


С правой и левой границами сложности нет: правая всегда равна rates[0].time или rates[3].time в зависимости от установки ArraySetAsSeries. А от нее отсчитываем нужное количество баров влево в зависимости от паттерна.

Решил так сделать (ведь универсальности пытаюсь добиться)... поскольку startBar и endBar теперь у нас в виде времени, то получим индексы этих баров на графике
int rightbar = iBarShift_(_Symbol,PERIOD_CURRENT,endBar,true);
int leftbar = iBarShift_(_Symbol,PERIOD_CURRENT,stratBar,true);

В итоге расчет будет вестись вот так с помощью дополнительных функций, аналогов MQL4

 цитата:

double lowPrice = iLow_(_Symbol,PERIOD_CURRENT, iLowest_(_Symbol,PERIOD_CURRENT,MODE_LOW, leftbar-rightbar+1,rightbar));
double highPrice = iHigh_(_Symbol,PERIOD_CURRENT, iHighest_(_Symbol,PERIOD_CURRENT,MODE_HIGH,leftbar-rightbar+1,rightbar));



Громоздко получилось? Пожалуй есть другой вариант более локоничный... Что-нибудь через MathMin и MathMax... Но конструкция кода еще продумал

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2483
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 24.04.17 19:20. Заголовок: evbut пишет: Аха.....


evbut пишет:

 цитата:
Аха... теперь затыка с границами паттернов, в частности с верхней и нижней в функции FindPatternsAndFillDB


В данном конкретном случае лучший выход - сделать функцию перебора по барам в поисках нужного экстремума, т. к. баров предполагается немного (4 - это действительно мало):

 цитата:

double GetExtremum(const MqlRates &starrRates[], int nBars, int nExtMode)
{
int nTotal = int(MathMin(nBars, ArraySize(starrRates)));
double fExtremum = 0.0;
for (int i = 0; i < nTotal; ++i)
{
if (nExtMode == MODE_HIGH && fExtremum < starrRates[ i ].high)
fExtremum = starrRates[ i ].high;

if (nExtMode == MODE_LOW && (fExtremum == 0.0 || fExtremum > starrRates[ i ].low))
fExtremum = starrRates[ i ].low;
}

return fExtremum;
}



Использование функции:

 цитата:
double fLow = GetExtremum(rates, patternBars, MODE_LOW);
double fHigh = GetExtremum(rates, patternBars, MODE_HIGH);



где patternBars - количество баров для того или иного паттерна.

Это вариант для использования без ArraySetAsSeries().

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 86
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 27.04.17 06:57. Заголовок: Scriptong пишет: гд..


Scriptong пишет:

 цитата:
где patternBars - количество баров для того или иного паттерна.


Понятно. Но, чтобы их получить, нужно будет использовать искусственную функцию перевода времени бара в индекс? В MQL5 нету iBarShift.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2486
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 01.05.17 11:09. Заголовок: evbut пишет: Понятн..


evbut пишет:

 цитата:
Понятно. Но, чтобы их получить, нужно будет использовать искусственную функцию перевода времени бара в индекс?


patternsBars - это количество, а не индекс. Поэтому ничего получать не нужно. Вместо patternsBars подставляется 2, 3 или 4 в зависимости от типа паттерна.

evbut пишет:

 цитата:
В MQL5 нету iBarShift.


Зато есть замечательная функция Bars, которая с лихвой покрывает возможности iBarShift от MQL4. Смотрите второй вариант функции:

 цитата:
int Bars(
string symbol_name, // имя символа
ENUM_TIMEFRAMES timeframe, // период
datetime start_time, // с какой даты
datetime stop_time // по какую дату
);


Если использовать ее следующим образом:

 цитата:
int nBarIndex = Bars(Symbol(), Period(), time, TimeCurrent());


то получим аналог iBarShift(). Единственный момент - могут быть смещения в +/-1 бар, если time попадает не на время открытия бара.




Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 87
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 03.05.17 10:34. Заголовок: Scriptong пишет: Ес..


Scriptong пишет:

 цитата:
Если использовать ее следующим образом:


Сделал в виде функции

 цитата:
int i_BarShift(datetime time)
{
return (Bars(_Symbol, PERIOD_CURRENT, time, TimeCurrent())-1);
}


Scriptong пишет:

 цитата:
Единственный момент - могут быть смещения в +/-1 бар, если time попадает не на время открытия бара.


Смещение на +1 бар как бы очевидное получается ведь в счет идет и текущий, так называемый "нулевой" бар. А в каких случаях и как часто бывает смещение на -1 бар? Как-то контролировать можно этот момент?

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2489
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 05.05.17 12:04. Заголовок: evbut пишет: Смещен..


evbut пишет:

 цитата:
Смещение на +1 бар как бы очевидное получается ведь в счет идет и текущий, так называемый "нулевой" бар.


В принципе, если нужно считать ровно так же, как и в MQL4, то лучше все-таки начинать поиск со времени на 1 секунду ранее, чем нулевой бар:

 цитата:

datetime dtTime0Bar[];
CopyTime(Symbol(), PERIOD_CURRENT, 0, 1, dtTime0Bar);
int nBarIndex = Bars(Symbol(), PERIOD_CURRENT, time, dtTime0Bar[0] - 1)


Это позволит не включать в интервал поиска нулевой бар, индекс которого при счете справа налево нам всегда известен.

evbut пишет:

 цитата:
А в каких случаях и как часто бывает смещение на -1 бар?


Когда третий и четвертый аргумент указывают на время внутри одного и того же бара, к примеру. В документации (см. примечание) этот момент специально описан.
Также возможен случай, когда третий аргумент указывает на время правее одного бара, который предполагается включить в расчет, а четвертый - чуть левее. Так и получим -1 от того значения, которое вернула бы функция iBarShift(). Она ведь работает несколько по-другому - использует округление к ближайшему бару.

evbut пишет:

 цитата:
Как-то контролировать можно этот момент?


Сравнить время открытия полученного бара со временем, указанным в третьем аргументе. Если данные равны, то все ОК, если нет, то вычесть или добавить 1. Это уже зависит от поставленной задачи.

Спасибо: 1 
ПрофильЦитата Ответить



Сообщение: 88
Зарегистрирован: 11.04.16
Откуда: Иркутск
Репутация: 0
ссылка на сообщение  Отправлено: 12.05.17 09:18. Заголовок: День добрый! Начал ..


День добрый!
Начал по-тихоньку продумывать логику мульти-пульти варианта. Хочется узнать ваше мнение о, так сказать, правильности и локоничности хода моих мыслей. В общем, чтобы находить тот или иной паттерн на разных символах и таймфреймах задумал создать главную (определяющую) структуру по символу(список символов), в состав которой входят данные с таймфреймов (список периодов и данные типа MqlRates для каждого периода):

 цитата:
struct TFInfo
{
ENUM_TIMEFRAMES tf;
string text;
MqlRates _symbol[];
BAR_TYPE bartype;

TFInfo()
{
Init();
}
void Init()
{
ArraySetAsSeries(_symbol,true);
bartype = NONE_BAR;
}
};
TFInfo g_tfInfo[MAX_PERIOD]; // Periods

struct SymbolData
{
string symbol;
TFInfo g_tfInfo[MAX_PERIOD];

SymbolData()
{
Init();
}
void Init()
{
symbol = "";
}
};
SymbolData g_symbdata[MAX_SYMBOLS]; // Symbols


Таким образом, чтобы получить данные на каждой свече последних 3 свечей будет вызваться CopyRates() в тройном цикле:

 цитата:
for (int k = limit; k > 0; k--) интерации по барам
for (int i = 0; i < ArraySize(g_symbdata); i++) интерации по символам
for (int j = 0; j < ArraySize(g_tfInfo); j++) интерации по периодам
{
if(!CopyRates(g_symbdata.symbol,g_symbdata.g_tfInfo[j].tf,k,3,g_symbdata.g_tfInfo[j]._symbol))
return false;
}


Проверку корректности получаемых данных провожу далее принтом:

 цитата:

for(int x = ArraySize(g_symbdata.g_tfInfo[j]._symbol)-1; x >=0; x--)
{
double high = g_symbdata.g_tfInfo[j]._symbol[x].high;
double low = g_symbdata.g_tfInfo[j]._symbol[x].low;
datetime time = g_symbdata.g_tfInfo[j]._symbol[x].time;

Print(g_symbdata.symbol + " Period [" + g_symbdata.g_tfInfo[j].text+ "] Bar from rates ["
+ IntegerToString(x) + "][" + TimeToStr(time) +
"] High = [" + high +
"] Low = [" + low +
"] Time = [" + TimeToStr (time, TIME_DATE|TIME_SECONDS) +
"]");


Анализ данных с принта и по графикам каждого символа и таймфрейма получается, что все необходимые данные для определения того же паттерна ППР у нас записаны в структуре.
Выходит далее к примеру в функции поиска бычьего паттерна ППР (IsBullsPPRPattern()) будет выглядеть так:

 цитата:
bool IsBullsPPRPattern(int index)
{
for (int i = 0; i < ArraySize(g_symbdata); i++)
for (int j = 0; j < ArraySize(g_tfInfo); j++)
for(int x = 0; x < ArraySize(g_symbdata.g_tfInfo[j]._symbol); x++)
{
if(g_symbdata.g_tfInfo[j]._symbol[0].close <= g_symbdata.g_tfInfo[j]._symbol[1].high) // Максимум предыдущей свечи не пробит
return(false); // Паттерн не сформирован

if (g_symbdata.g_tfInfo[j]._symbol[1].low >= g_symbdata.g_tfInfo[j]._symbol[2].low || // Минимум предыдущего бара не..
g_symbdata.g_tfInfo[j]._symbol[1].low >= g_symbdata.g_tfInfo[j]._symbol[0].low) // ..является минимумом паттерна
return(false); // Паттерн не сформирован

if (g_symbdata.g_tfInfo[j]._symbol[2].close >= g_symbdata.g_tfInfo[j]._symbol[2].open) // Стартовый бар паттерна не является
return(false); // ..медвежьим - выход*/
}

return(true); // Паттерн сформирован
}


Что скажите? Громоздко по-моему все получается... Для каждой функции поиска паттерна тройные циклы. Это все же пока набросок. Вызов функций разумеется в дальнейшем будет происходить не в OnCalculate, а через OnTimer... Файл черновика ПРИЛАГАЕТСЯ

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2494
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 16.05.17 18:18. Заголовок: Все намного проще. У..


Все намного проще. У Вас уже имеется код для работы с одним символом. Далее требуется вызывать его точно также, но с одним фиксом: передать в него имя символа.
Так, на сегодня имеется функция ShowIndicatorData. Она работает с текущим символом. Чтобы сделать ее универсальной, требуется всего лишь передать ей имя символа, с которым необходимо работать. И далее внутри этой функции передать имя символа подчиненным функциям:

 цитата:
bool ShowIndicatorData(string strSymbol, int limit)
{
for (int i = limit; i > 0; i--)
{
if (!FindPatternsAndFillDB(strSymbol, i))
return false;

if (ShowWorkedPattern == NO)
continue;

ProcessSLAndTPOfPatterns(strSymbol, i);
}

return true;
}


В итоге для расчета паттернов по нескольким символам потребуется всего лишь один цикл:

 цитата:
for (int i = ArraySize(g_symbdata) - 1; i >= 0 ; --i) // итерации по символам
ShowIndicatorData(g_symbdata[ i ], limit);



Правда в данном случае еще нужно для каждого символа рассчитать свое значение limit.

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2495
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 16.05.17 18:21. Заголовок: Кстати, поставленная..


Кстати, поставленная задача (мультивалютный индикатор) как нельзя лучше решается через ООП. Ведь в данном случае достаточно взять готовый код, сделать из него класс, а уже класс тиражировать для разных символов. Таким образом, отпадает даже необходимость в индивидуальном расчете значения limit, т. к. это уже есть в коде.

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 87 , стр: 1 2 3 4 5 6 All [только новые]
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  2 час. Хитов сегодня: 0
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет