Отправлено: 16.12.16 05:39. Заголовок: Паттерны ПрайсЭкшен через структуру
Игорь добрый день! Перенесу сюда свои мытарства с перепрограммированием индикатора по паттернам под свои нужды. В той ветке я показал, что кое-какие сдвиги к получению желаемого мной результата есть. В текущем варианте как вы видели по картинкам он уже отрисовывает паттерны и их цели, способен перекрасить паттерны, если его таргет пробит. Вопрос по удалению перекрытых паттернов пока откладываю на потом, поскольку возник более актуальный. Повторю здесь кусок кода, где происходят главные события с паттернами: Скрытый текст
цитата:
void FindAndShowPatterns(int index) { int startBar, patternDir,patternName; GetData(index,startBar,patternDir,patternName);
double lowPrice = ND(Low[iLowest(NULL, 0, MODE_LOW, // Нижняя граница паттерна startBar - index + 1, index)]);
double highPrice = ND(High[iHighest(NULL, 0, MODE_HIGH, // Верхняя граница паттерна startBar - index + 1, index)]); double patternHeight = highPrice - lowPrice;
Но тут где-то собака зарылась, не пойму относительно отображения EnumToString(pattern.getTarget), которая определяется отдельной функцией (кстати подобными строками перекрашиваются паттерны):
Так вот... Eсли медвежий паттерн отработан (WORKED) - то окрашивается он как отработанный, и в подписи к нему EnumToString(pattern.getTarget) пишет WORKED, а вот с бычьими почему-то не пишет... окрашивает как отработанный, но в подписи и в принте пишет что он актуальный (см. рис). Как побороть это недоразумение? Сдается мне что тут вина в implicit enum conversion в строке g_patterns[patternArray].getTarget = getTarget, его энум Скрытый текст
Кроме этого таких предупреждений еще два штуки есть по коду в строках: g_patterns[patternArray].patternType = patternDir, его Энум выглядит так Скрытый текст
Ну и все они в структуре объявлены и инициализированы вот так patternType = NONE_TYPE; patternName = NONE_INDEX; getTarget = NONE; И на всякий случай функция GetData Скрытый текст
цитата:
void GetData(int index, int& startBar, int &type, int &patternName) { //- 1 - == Определим тип найденного паттерна по направлению ===================== if(IsBullsRailsPattern(index)|| IsBUOVBPattern(index) || IsBullsPPRPattern(index)) type = BULL_TYPE; if(IsBearsRailsPattern(index) || IsBEOVBPattern(index)|| IsBearsPPRPattern(index)) type = BEAR_TYPE; //- 1 - == Конец ===============================================================
Просмотрев немного по истории, точной закономерности не выявил, но вот покажу участок, где стрелками показаны два по рассраске отработанных бычьих паттерна, между ними 8 свечей (две стрелки указывают на один и тот паттерн). Но подписи у них разные... тот что ниже слева - пишет WORKED, а тот что через 8 свечей справа - ACTUAL.
Чо к чему... не пойму А главное как так-то? Может в коде какого дополнительного условия не хватает в функции IsActualPattern? Или это не понятные примудрусти какие-то в функции строки подписи? Скрытый текст
Отправлено: 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 вылазит ошибка выхода за пределы массива (( Чот видать не туда шагать начал ((
Отправлено: 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 изменяется на противоположную. Причем в достаточно сложном сочетании, т. к. нулевой элемент всякий раз указывает на разный бар. С этим фактом всегда ломается огромное количество копий.
Имейте в виду, что нумерация баров после использования функций типа Copy изменяется на противоположную. Причем в достаточно сложном сочетании, т. к. нулевой элемент всякий раз указывает на разный бар. С этим фактом всегда ломается огромное количество копий.
ArraySetAsSeries(rates,true) не помогает в этом случае? И как обычно борются с этой напастью?
Отправлено: 03.04.17 20:00. Заголовок: evbut пишет: Решил ..
evbut пишет:
цитата:
Решил проблему. Не знаю на сколько оправдано, тем не менее работает и в МТ4 и в МТ5. CopyRates(NULL,0,0,rates_total,rates)
Не-не, очень плохо. Зачем Вам весь массив данных, если максимум четыре бара для поиска паттерна требуется? Просто на каждом баре запрашивайте четыре последних свечи:
Имеется в виду, что nBarIndex - это текущий обрабатываемый бар (тот, который в главном цикле задается). От него, включая его, запрашивается всего 4 бара. Это достаточно быстрая операция. Если выполнение функции успешно завершено, то в элементе 0 массива stRates будут данные о баре (nBarIndex + 3), в элементе 1 - данные от (nBarIndex + 2), в элементе 2 - данные (nBarIndex + 1) и в элементе 3 - от бара nBarIndex.
P. S. Кстати, в MQL5 конструкция CopyRates(NULL, 0...) работать не будет. Обязательно требуется CopyRates(Symbol(), PERIOD_CURRENT...).
Отправлено: 04.04.17 20:54. Заголовок: evbut пишет: Без Ar..
evbut пишет:
цитата:
Без ArraySetAsSeries не отображаются паттерны, а с ним отображаются
Я же говорю - массив переворачивается. А ArraySetAsSeries переворачивает его обратно, в таймсерию. Если не хочется переписывать функции поиска паттернов, то да, нужен ArraySetAsSeries. Но в этом случае код получается не адаптированным, а именно переведенным (как Google Translate переводит с одного языка на другой) на MQL5. То есть по-хорошему для универсального кода нужно переписать функции поиска паттернов, развернув в них нумерацию баров.
evbut пишет:
цитата:
Хм... а ведь работает
Сейчас работает, но нет гарантий, что будет работать в будущем. Это недокументированная возможность, перешедшая с MQL4. Поменяют MetaQuotes значения перечислений, и тогда все подобные коды полетят в тартарары.
То есть по-хорошему для универсального кода нужно переписать функции поиска паттернов, развернув в них нумерацию баров.
Ну да... поглядел несколько кодов на 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 данные только первого бара.
Отправлено: 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 бара - разницы практически никакой. Другое дело, если бы речь шла о тысячах баров. Тогда нужно было бы что-то придумывать.
Ну и далее в каждой функции поиска паттерна через цикл for(int i = 0; i < ArraySize(g_candles); i++) исправляем всякие Close, High и Low и проч на данные из этой структуры Не тот маршрут выбрал? )))
Пока не понял преимущество такой надстройки. В моих кодах для таких целей пока хватало стандартной структуры MqlRates. То есть вместо того, чтобы использовать стандартные таймсерии, достаточно один раз на каждой итерации цикла запросить данные о последних 4-х барах и передать эту структуру всем функциям, которые используют данные для свечей.
Отправлено: 10.04.17 06:02. Заголовок: Это понятно, что коп..
Это понятно, что копировать на каждой i данные только 4х свечей включая саму i. Не поятен мне вопрос по смене логики, чтобы и в mql4и mql5 работало без ArraySetSeries.
Отправлено: 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. То есть все индексы "перевернуты".
Отправлено: 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 и львиная доля её использует.
Все даты в формате GMT
2 час. Хитов сегодня: 0
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет