Форум » Индикаторы » Простые паттерны Price Action » Ответить

Простые паттерны Price Action

evbut: Добрый день! Уж простите коль не в нужном месте тему создал. Хотел выразить большое спасибо автору советника и индикатора по прайсэкшен, которые обнаружил ЗДЕСЬ. Поиск самого автора привел меня сюда. Мне интересна тема прайсэкшен и торгую по ней, в основном рельсы, поглощение, PPR. Но использую другой подход - ТП рассчитываю через фибо от величины паттерна. Хотелось бы расположенный по ссылке советник адаптировать под свою стратегию, т.е. убрать из него автооптимизацию и автоподстановку СЛ и ТП, а ввентить установку ТП через фибо (параметр настраиваемый) и СЛ, который устанавливается на вершине (для продаж) или дне паттерна (для покупок). Буду премного благодарен, если отзовется автор или кто другой кто сможет переделать советник

Ответов - 35, стр: 1 2 3 All

Scriptong: Добрый день. Это сделать достаточно легко: 1. Строки: extern string A2 = "Профит в пунктах от цены открытия позиции"; extern int defaultTP = 50; заменить на: extern string A2 = "Профит в % от высоты паттерна"; extern double percentTP = 131.8; 2. Функцию GetTP заменить на такую: double GetTP(int patternDir, int patternStart) { RefreshRates(); double patternHigh = iHigh(NULL, 0, iHighest(NULL, 0, MODE_HIGH, patternStart, 1)); double patternLow = iLow(NULL, 0, iLowest(NULL, 0, MODE_LOW, patternStart, 1)); double patternHeight = patternHigh - patternLow; if (patternDir == PATTERN_BEAR) return (patternHigh - patternHeight * percentTP / 100.0); return (patternLow + patternHeight * percentTP / 100.0); } 3. Запускать с отключенной автооптимизацией.

evbut: Scriptong пишет: 2. Функцию GetTP заменить на такую: Спасибо большое за оперативность. Ваше предложение работает! Если не затруднит Вас, хотел бы еще попросить Вас подправить или дайть совет-наводку как самому подправить вот такой момент. Если отключаю закрытие по противоположному сигналу, советник открывает ордера и в бай и селл - в принципе так и надо для меня, но хотелось бы, чтоб в рынке могло быть только 1 ордер бай и один ордер селл (одновременно), каждый из которых при появлении паттерна в соответствующую сторону модифицировался, т.е. ТП и СЛ переносился бы при условии, что уровень ТП нового паттерна ваше/ниже предыдущего (см. картинку), а СЛ под/над новый паттерн. Сейчас если убираю из кода if (g_type == OP_BUY) if (!CloseDeal(g_ticket)) return(false); он открывает несколько ордеров бай и селл, а как модификация происходит не пойму что-то.

Scriptong: evbut пишет: Если не затруднит Вас, хотел бы еще попросить Вас подправить или дайть совет-наводку как самому подправить вот такой момент. Если отключаю закрытие по противоположному сигналу, советник открывает ордера и в бай и селл - в принципе так и надо для меня, но хотелось бы, чтоб в рынке могло быть только 1 ордер бай и один ордер селл (одновременно), каждый из которых при появлении паттерна в соответствующую сторону модифицировался, т.е. ТП и СЛ переносился бы при условии, что уровень ТП нового паттерна ваше/ниже предыдущего (см. картинку), а СЛ под/над новый паттерн. Для этого советник нужно переписывать полностью. Он станет несколько сложнее. Ведь в текущем представлении он потому и является таким простым, что работает с одним ордером. evbut пишет: Сейчас если убираю из кода  цитата: if (g_type == OP_BUY) if (!CloseDeal(g_ticket)) return(false); он открывает несколько ордеров бай и селл, а как модификация происходит не пойму что-то. Конечно. Ведь в таком случае советник попросту теряет свои ордера. Вы убрали из кода контроль за тем, что в рынке всегда присутствует только один ордер советника. В итоге советник на каждом тике случайным образом получает информацию только об одном из своих открытых ордеров. Остальные "теряются".


evbut: Scriptong пишет: Для этого советник нужно переписывать полностью. Он станет несколько сложнее. Вам как специалисту и автору советника да и практически всего, что здесь есть (многое что почитал здесь у Вас) видней. Спасибо, что не прошли стороной. Попробую самостоятельно подогнать имеющийся код под свою идею. Примеров полно здесь и учебник по MQL мне в помощь

Scriptong: evbut пишет: Попробую самостоятельно подогнать имеющийся код под свою идею. Примеров полно здесь и учебник по MQL мне в помощь В учебнике есть для этого специальная глава Учет ордеров. Что-то вроде этого нужно будет организовать в собственном советнике, чтобы работать со множеством ордеров.

evbut: Еще раз здравствуйте! Для ручной торговли немного урезал и модифицировал индикатор PriceAction, добавив в него отображение уровне целей по фибо. На картинке в предыдущем посте их видно. Есть желание еще маленько подправить отображение как самих паттернов, так и их уровней целей. А именно, чтобы при заданном количестве используемых баров истории ( indBarsCount = 500) была возможность выбрать отображать либо все имеющиеся графические объекты (паттерны и их цели), либо только те, которые еще, так скажем не отработаны. Под "не отработанными паттернами" подразумевается, что цена не была на уровне цели (черточка на картинке предыдущего поста). Как это реализовать - затруднительно для меня, т.к. далеко начинающий программист ) Для реализации этой задачи, мне видится, необходимо выполнить следующее: 1. Произвести поиск бара, с которого ведется отсчет для построений. 2. На этом участке найти максимальную и минимальную цену - этим мы определим диапазон цен 3. Сравнить была ли черточка (линия цели) в этом диапазоне или находится за его пределами 3.1. если была - удалить (или не отображать) объекты иначе оставить до тех пор пока цена не побывает на это уровне С первым пунктом понятно он есть в индикаторе в функции int GetRecalcIndex(int& total). //+-------------------------------------------------------------------------------------+ //| Определение индекса бара, с которого необходимо производить перерасчет | //+-------------------------------------------------------------------------------------+ int GetRecalcIndex(int& total) { int counted_bars = IndicatorCounted(); // Сколько баров уже посчитано total = Bars - 1; // Определение первого бара истории if (indBarsCount > 0 && indBarsCount < total) // Если не нужно рассчитывать всю.. total = indBarsCount; // ..историю, то начнем с указанного.. // ..бара - indBarsCount if (counted_bars == 0) // Кол-во посчитанных баров - 0. { DeleteAllObjects(); // Не забудем удалить все созданные.. // ..объекты return(total); // Нужно пересчитать всю историю } return(Bars - counted_bars - 1); // Начинаем с первого непосчитанного.. // ..бара } Функция удаления объектов тоже есть //+-------------------------------------------------------------------------------------+ //| Удаление всех объектов, созданных индикатором | //+-------------------------------------------------------------------------------------+ void DeleteAllObjects() { for (int i = ObjectsTotal()-1; i >= 0; i--) if (StringSubstr(ObjectName(i), 0, StringLen(PREFIX)) == PREFIX) ObjectDelete(ObjectName(i)); } Подскажите в какую сторону капать? Функцию удаления нужно будет править, добавив в нее поиск объекта в диапазоне цен или же создать отдельную функцию типа DelObjectAfterGetTarget? Прикрутил файл индикатора на всякий случай https://yadi.sk/d/nZxAAhreqwjwD

Scriptong: evbut пишет: Под "не отработанными паттернами" подразумевается, что цена не была на уровне цели (черточка на картинке предыдущего поста). Как это реализовать - затруднительно для меня, т.к. далеко начинающий программист ) Для реализации этой задачи, мне видится, необходимо выполнить следующее: 1. Произвести поиск бара, с которого ведется отсчет для построений. 2. На этом участке найти максимальную и минимальную цену - этим мы определим диапазон цен 3. Сравнить была ли черточка (линия цели) в этом диапазоне или находится за его пределами 3.1. если была - удалить (или не отображать) объекты иначе оставить до тех пор пока цена не побывает на это уровне Да, рассуждения верные. После нахождения паттерна нужно произвести сканирование истории в будущее (вправо по графику) до бара, на котором будет найден следующий паттерн. На этом участке найти границы минимума и максимума и сравнить их с заданной ценой. То есть внутри цикла перебора баров нужно организовать еще один цикл. По самой же сути новшества. Такие индикаторы называются перерисовывающимися. К ним отношение у всех отрицательное, т. к. они вводят трейдеров в заблуждение - на истории выглядят отлично, а в реальности ни на что не годятся. Поэтому при разработке любого индикатора нужно всегда проверять, не заглядывает ли он в будущее.

evbut: Scriptong пишет: По самой же сути новшества. Такие индикаторы называются перерисовывающимися. К ним отношение у всех отрицательное, Вы хотите сказать, что идея не отображения "неотработавших" паттернов приведет к перерисовыванию индикатора? но он же не будет таковым, т.к. шарить он будет только по истории слева направо до 1 бара или до поледнего сформировавшегося паттерна, который уж точно не будет отработанным.

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

evbut: Scriptong пишет: Если же в процессе работы индикатора цена все же достигнет цели и после этого трейдер переинициализирует индикатор, то такой паттерн появится, хотя до этого его не было на графике. Трейдер хватается за голову "такой сигнал пропустил!" Это как раз и есть перерисовка, у которой два варианта: показывать то, что ранее не показывали, или стирать то, что показали ранее, но потом что-то пошло не так. Ситуация как раз таки противоположная - стиреть то, что прошло так как надо. Но этот вопрос не принципиален. Вполне удобно видеть все, что было ) По поводу советника, думал-гадал и кажется мне, что оптимальным будет использовать имеющиеся функции получения сигнала, но их разбить на PATTERN_BULL и PATTERN_BEAR, каждый из которых будет выводиться в свою соответствующую его направлению функцию. Функция работы с бычьими сигналами и функция для работы с медвежьими. Каждая из них будет открывать и модифицировать только свои ордера. Как вы оцените такой подход к решению моей задачи?

Scriptong: evbut пишет: Ситуация как раз таки противоположная - стиреть то, что прошло так как надо. То есть нужно видеть только те сигналы, которые привели к убытку? Достаточно странная постановка задачи На мой взгляд, лучше сделать следующим образом: показывать все, но ввести дополнительный функционал. Он будет заключаться как раз в оценке качества того или иного паттерна. Тот, который не привел к достижению цели, показать одним цветом, а тот, который привел - другим цветом. evbut пишет: По поводу советника, думал-гадал и кажется мне, что оптимальным будет использовать имеющиеся функции получения сигнала, но их разбить на PATTERN_BULL и PATTERN_BEAR, каждый из которых будет выводиться в свою соответствующую его направлению функцию. Функция работы с бычьими сигналами и функция для работы с медвежьими. Каждая из них будет открывать и модифицировать только свои ордера. Как вы оцените такой подход к решению моей задачи? Такой вариант подойдет только в том случае, если по одному направлению планируется не более одного ордера. Но в принципе любую стратегию стоит разбивать на задачи по-другому: есть сигнальный модуль и есть модуль, обрабатывающий имеющиеся ордера. Сигнальный модуль, как и положено, только генерирует сигналы. А вот модуль работы с ордерами должен реагировать на сигналы и, в зависимости от сигнала, открывать или закрывать ордера. В принципе, именно так и сделано в исходном советнике. Просто модуль обработки ордеров не рассчитан на работу с двумя и более ордерами. Вот этот модуль и нужно дорабатывать, составляя список своих ордеров с записью в массив, а уже этот массив обрабатывать.

evbut: Scriptong пишет: Да, рассуждения верные. После нахождения паттерна нужно произвести сканирование истории в будущее (вправо по графику) до бара, на котором будет найден следующий паттерн. На этом участке найти границы минимума и максимума и сравнить их с заданной ценой. То есть внутри цикла перебора баров нужно организовать еще один цикл. День добрый! Хочется всё же реализовать такую возможность. Только вот запутался и кажется прилично. Используя код вашего индикатора со статистикой нашел такой кусок кода, где как раз производится поиск паттернов на истории. Напомню его вам, только маленько я его уже подправил (надеюсь верно) для своих целей: //+-------------------------------------------------------------------------------------+ //| Поиск паттернов указанного типа в истории | //+-------------------------------------------------------------------------------------+ void FindPatterns(int patternType, int total, int& patternCnt, int& patternIndex[], int& patternDir[], double& BullsTargets[], double& BearsTargets[]) { int patternStart; for (int i = 2; i < total; i++) // Идем справа налево по графику,.. { // ..проверяя наличие паттерна на.. int direction = GetPatternDirection(i, total, // .. каждом баре patternType, patternStart); if (direction == PATTERN_NO) // Паттерна нет - идем дальше continue; //найдем переменные для расчетов уровней ТП для бычьих и медвежьих паттернов double lowprice = Low[iLowest(NULL,0,MODE_LOW,patternStart - i + 1, i)]; double highprice = High[iHighest(NULL,0,MODE_HIGH,patternStart - i + 1, i)]; double patternHeight = highprice - lowprice; // ------- нашли --------------------------------------------------------------------------- patternIndex[patternCnt] = i; // Паттерн есть - запишем номер бара, patternDir[patternCnt] = direction; // ..направление паттерна,.. if (direction == PATTERN_BULL) // ..и рассчитаем уровень ТП BullsTargets[patternCnt] = lowprice + patternHeight * FiboTarget / 100.0; else BearsTargets[patternCnt] = highprice - patternHeight * FiboTarget / 100.0; patternCnt++; // Количество паттернов увеличилось } } Если я правильно понимаю логику этого куска, то по запросу он должен выдать общее количество всех паттернов в виде массива, их направление, а также выдать массивы целей бычьих и медвежьих паттернов. Теперь получается мне необходимо на участке истории for (int i = limit; i > 0; i--) сравнивать массивы целей с хай и лоу каждой свечи. В этом же месте это делать или в отдельной функции? И еще такой момент. Представленный выше кусок подходит для нахождения непосредственно паттернов, поскольку отрисованные паттерны на графике на сколько я понимаю лишь прямоугольники. Они не находятся в виде массива? Подправленная версия с таргетами как показывал на картинке здесь отображает эти самые таргеты которые хранятся в виде переменной BuyTP и SellTP, которые можно прописать в массив. Во всяком случае когда я принтую одну из этих переменных, то отображаются действительные ценовые уровни, те что расчитываются и наносятся на график. Кусок кода где рассчитываются чтобы потом отобразиться - для бычьих паттернов: void ShowBullPattern(int startIndex, int endIndex, color clr, int patternType, string description) { // - 1 - == Поиск верхней и нижней границ паттерна ====================================== double lowPrice = Low[iLowest(NULL, 0, MODE_LOW,// Нижняя граница паттерна startIndex - endIndex + 1, endIndex)]; double highPrice = High[iHighest(NULL, 0, // Верхняя граница паттерна MODE_HIGH, startIndex - endIndex + 1, endIndex)]; double patternHeight; // - 1 - == Окончание блока ============================================================= // - 2 - == Отображение прямоугольника ================================================== datetime leftTime = Time[startIndex]; // Начальное время паттерна datetime rightTime = Time[endIndex]; // Конечное время паттерна string name = GetObjectName(endIndex, patternType, FIRST_PART);// Имя объекта паттерна ShowRectangle(name, leftTime, lowPrice, // Отображение объекта rightTime, highPrice, description, clr); // - 2 - == Окончание блока ============================================================= // - 3 - == Расчет ТП ================================================================== patternHeight = highPrice - lowPrice; BuyTP = lowPrice + patternHeight * FiboTarget / 100.0; name = GetObjectName(endIndex, patternType, SECOND_PART); //имя объекта ТП ShowBullTarget(name, leftTime, BuyTP, rightTime, BuyTP, description, clr); } Может имеет смысл по этому пути пойти. Взять все эти BuyTP и SellTP в виде массива, и прогнать по истории for (int i = limit; i > 0; i--) сравнивая с хай и лоу каждой последующей свечи, чтобы потом перекрасить прямоугольник паттрена? Вот только я, как абсолютный новичок в кодировании не совсем соображаю как мне сравнивать две группы массивов - массивы таргетов и массивы хай и лоу. Просто по ценам сравнить наверно будет не правильно... нужно же еще привязку по свечам делать или нет? В общем в замешательстве и путанице. Помогите распутаться, пожалуйста! С уважением Евгений.

Scriptong: evbut пишет: Если я правильно понимаю логику этого куска, то по запросу он должен выдать общее количество всех паттернов в виде массива, их направление, а также выдать массивы целей бычьих и медвежьих паттернов. Такой подход даст лишь сами уровни целей для каждого паттерна. Но ведь нужно еще проверить, были ли достигнуты эти уровни на участке истории между одним паттерном и другим. Поэтому делать отдельную функцию после вызова FindPatterns - это выполнение одной и той же работы дважды. Недостающий функционал нужно располагать именно в FindPatterns. evbut пишет: Может имеет смысл по этому пути пойти. Взять все эти BuyTP и SellTP в виде массива, и прогнать по истории for (int i = limit; i > 0; i--) сравнивая с хай и лоу каждой последующей свечи, чтобы потом перекрасить прямоугольник паттрена? Это то же самое, о чем я говорил выше - двойной труд. Следует расширять обязанности FindPatterns, дробя ее на вызовы других функций.

evbut: Scriptong пишет: Но ведь нужно еще проверить, были ли достигнуты эти уровни на участке истории между одним паттерном и другим. Проверить необходимо не между паттернами, а от момента формирования паттерна до первой свечи. И так с каждым паттерном в истории и тем что сформировался на на предыдущей свече. Буду копать дальше. Еще маленькая просьба поправьте если я не прав. Вот чтобы сравнить уровень цели, допустим BuyTP, c хаями каждой последующей свечи после формирования паттерна я должен прописать так? for(int i = endIndex - 1; i > 0; i--) { if(BuyTP > High[endIndex -1 - i]) то выполнить то-то

Scriptong: evbut пишет: Проверить необходимо не между паттернами, а от момента формирования паттерна до первой свечи. И так с каждым паттерном в истории и тем что сформировался на на предыдущей свече. Тогда подход должен быть совершенно другой, сложнее. Почему сложнее? Потому что нужно "помнить" информацию о каждом паттерне (месте формирования, его параметрах, целях), а с появлением каждой новой свечи (даже каждой новой цены, т. е. на каждом тике) проверять, не была ли достигнута заданная цель по каждому из несработавших паттернов. Как только достигнута цель, то паттерн удаляется (или отображается, смотря, что нужно). Таким образом, алгоритм будет примерно такой: 1. Поиск паттерна. 2. Запись паттерна в базу данных паттернов. 3. Проверка "срабатывания" паттерна. 4. Если паттерн "сработал", он удаляется из базы данных и происходит коррекция его отображения (удаление или отображение на графике). Это далеко не три-четыре строки кода. Сложность чуть ниже среднего уровня программирования.

evbut: Scriptong пишет: Это далеко не три-четыре строки кода. Сложность чуть ниже среднего уровня программирования. Далеко мне еще до этого уровня ))) Но вот читаю код индикатора простых паттернов со статистикой и думаю, что из него можно что-то переделать под мою задачу. А именно вот какие куски кода интересны и думаю будут полезны. Для Scriptong пишет: 1. Поиск паттерна. 2. Запись паттерна в базу данных паттернов. использовать функцию FindPattern - ей мы находим все паттерны в истории и создаем их базу с таргетами patternIndex[patternCnt] = i; // Паттерн есть - запишем номер бара, patternDir[patternCnt] = direction; // ..направление паттерна,.. if (direction == PATTERN_BULL) // ..и рассчитаем уровень ТП BullsTargets[patternCnt]= if(direction ==PATTERN_BEAR) BearsTargets[patternCnt] = Далее для 3. Проверка "срабатывания" паттерна. можно использовать код функции GetPatternProfit, где производится расчет "срабатывания" паттерна, только там берется промежуток между паттернами for (int i = finish-1; i >= start; i--) , но можно его переделать в режим "от конца паттерна до первой свечи, где в этом промежутке будем сравнивать таргеты с наибольшим хаем и наименьшим лоу и передавать результат сравнения в функцию, которая будет закрашивать отработанные паттерны в другой цвет (согласен с Вами - этот вариант лучше). Копаю дальше )

Scriptong: evbut пишет: можно использовать код функции GetPatternProfit, где производится расчет "срабатывания" паттерна, только там берется промежуток между паттернами Здесь как раз можно проще - использовать последнюю известную цену (обрабатываемую свечу) для сравнения достижения цели. То есть не нужно перебирать все свечи от паттерна до конца истории. Это будет делаться на этапе поиска новых паттернов, а затем на обработке каждого нового тика.

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

Scriptong: evbut пишет: Не... не по силам мне все это Взываю к Вашей помощи К примеру, имеются массивы целей Buy и Sell от паттернов: double buyTargets[], sellTargets[]; // Заполнение массивов с постепенным изменением размера каждого из них Это наша "база данных". Далее достаточно на каждом тике проверить, есть ли достижение цели того или иного паттерна: int arraySize = ArraySize(buyTargets); for (int i = 0; i < arraySize; i++) if (Bid >= buyTargets[ i ]) { // Удаление паттерна из массива, т. к. он отработал } Аналогично для Sell-целей: int arraySize = ArraySize(sellTargets); for (int i = 0; i < arraySize; i++) if (Bid <= sellTargets[ i ]) { // Удаление паттерна из массива, т. к. он отработал }

evbut: Scriptong пишет: Это наша "база данных". Далее достаточно на каждом тике проверить, есть ли достижение цели того или иного паттерна: Добрый день, Игорь. Очень признателен вам за оперативное участие в решении моего вопроса. Увидел ваше сообщение уже после того как сам "навыдумывал" код. Сильно не смейтесь только ))) Пока решил оставить перекрашивание отработанных паттернов в другой цвет. Вот что нашаманил, но не отображается... //+-------------------------------------------------------------------------------------+ //| Поиск паттернов указанного типа в истории | //+-------------------------------------------------------------------------------------+ int FindHistoryPatterns(int patternType, int total, int& patternCnt, int& patternIndex[], int& patternDir[], double& BullsTargets[], double& BearsTargets[]) { int patternStart, condition; // - 1 - ====== Найдем все паттерны в истории =========================================== for (int i = 2; i < total; i++) // Идем справа налево по графику,.. { // ..проверяя наличие паттерна на.. int direction = GetPatternDirection(i, total, // .. каждом баре patternType, patternStart); if (direction == PATTERN_NO) // Паттерна нет - идем дальше continue; patternIndex[patternCnt] = i; // Паттерн есть - запишем номер бара, patternDir[patternCnt] = direction; // ..направление паттерна,.. // и расчитаем уровни целей //в зависимости от направления if(direction == PATTERN_BULL) BullsTargets[patternCnt] = Low[iLowest(NULL,0,MODE_LOW,patternStart - i + 1, i)] + (High[iHighest(NULL,0,MODE_HIGH,patternStart - i + 1, i)] - Low[iLowest(NULL,0,MODE_LOW,patternStart - i + 1, i)]) * FiboTarget /100; if(direction ==PATTERN_BEAR) BearsTargets[patternCnt] = High[iHighest(NULL,0,MODE_HIGH,patternStart - i + 1, i)] - (High[iHighest(NULL,0,MODE_HIGH,patternStart - i + 1, i)] - Low[iLowest(NULL,0,MODE_LOW,patternStart - i + 1, i)]) * FiboTarget / 100; patternCnt++; // Количество паттернов увеличилось } RefreshRates(); ArrayResize(patternIndex, total); // Максимальное кол-во паттернов на.. ArrayResize(patternDir, total); // ..этом участке истории ArrayResize(BullsTargets,total); ArrayResize(BearsTargets,total); for (i = patternCnt-1; i >= 0; i--) // По массиву паттернов { if(direction == PATTERN_BULL) { if(High >= BullsTargets) return (GETED_TARGET); else return(UNGETED_TARGET); } if(direction == PATTERN_BEAR) { if(Low <= BearsTargets) return(GETED_TARGET); else return(UNGETED_TARGET); } } return(condition); } Тут как бы понятно, что находим паттерны в истории с их таргетами, записываем их в массивы и паттерны и таргеты с привязкой к паттерну. В целом же думаю, чтобы эта функция возвращала состояние отработанности (GETED_TARGET или UNGETED_TARGET), которая передается в функцию FindAndShowPatterns (через нее настраивается отображение паттернов), которую подправляю, чтобы согласно полученному condition изменялся цвет отображаения паттернов. Кусочек этой функции: static datetime lastAlert = 0; int patternType, patternCnt, patternIndex[], patternDir[]; double BullsTargets[], BearsTargets[]; int condition = FindHistoryPatterns(patternType, total, patternCnt,patternIndex, patternDir, BullsTargets, BearsTargets); color clr; if(!IsGetedTarget && condition == UNGETED_TARGET) clr = colorBulls; // для бычьих паттернов if(IsGetedTarget && condition == GETED_TARGET) clr = GetTargetColor; Мне кажется косяк где-то зарыт в первом куске кода... Не передается этот кондишн (( С уважением Евгений.

Scriptong: evbut пишет: Мне кажется косяк где-то зарыт в первом куске кода.. Не только там, а везде Так, во втором куске кода объявлены переменные и массивы, но ничто не инициализировано. В переменных - мусор, массивы имеют нулевой размер. В итоге тело функции FindHistoryPattern пишет данные не в массивы, а неизвестно куда. По большому счету это фатальная ошибка исполнения. Если поставить в начале индикатора: #property strict то как раз на фатальную ошибку и получим. При этом, думаю, сами и сможете разобраться, в чем причина - массивы не имеют размера. Ведь размер массивов в первом куске кода указывается только после того, как произошла в них запись данных. Это то же самое, что загружать товар в вагоны, но вагоны подавать уже после загрузки. Спрашивается: куда же мы загружали товар, если вагонов не было?

evbut: И снова я со своими тараканами))) Здрасьте. Игорь, предложенный вами вариант сравнения элементов массивов таргетов с Bid как бы не совсем то, чтобы хотелось видеть, ибо при каждом новом запуске индикатор все будет делать заново относительно уже другой цены бид и не факт, что запустив его снова через день другой от перекрасит или удалит теже отработанные паттерны, что при запуске до этого. Поэтому хочется все же по более верному пути пойти, а именно через сравнения таргетов с хаем или лоем последующих новых свечей, т.е. от правой свечи паттерна вплоть до 0 к примеру. На сегодняшний момент имею вот такие подправленные функции: 1. ф-ция нахождения паттерно в истории в зависимости от направления //+-------------------------------------------------------------------------------------+ //| Поиск паттернов указанного типа в истории | //+-------------------------------------------------------------------------------------+ void FindPatterns(int total, int& BullpatternCnt, int& BearpatternCnt, int& BullpatternIndex[], int& BearpatternIndex[],double& BullpatternTP[], double& BearpatternTP[], int& BullTPIndex[],int& BearTPIndex[], int& GetTP) { int patternStart, dir; double lowPrice, highPrice, patternHeight; for (int i = 2; i < total; i++) // Идем справа налево по графику,.. { // ..проверяя наличие паттерна на.. patternStart = StartIndex(i,total); dir = Direction(i, total); lowPrice = Low[iLowest(NULL, 0, MODE_LOW, // Нижняя граница паттерна patternStart - i + 1, i)]; highPrice = High[iHighest(NULL, 0,MODE_HIGH, // Верхняя граница паттерна patternStart - i + 1, i)]; patternHeight = highPrice - lowPrice; if(dir == PATTERN_BULL) { BullpatternCnt++; BullpatternIndex[BullpatternCnt] = i; BullTPIndex[BullpatternCnt]= i; // Паттерн есть - запишем номер бара BullpatternTP[BullpatternCnt] = lowPrice + patternHeight * FiboTarget / 100.0; } if(dir==PATTERN_BEAR) { BearpatternCnt++; BearpatternIndex[BearpatternCnt] = i; BearTPIndex[BearpatternCnt] = i; BearpatternTP[BearpatternCnt] = highPrice - patternHeight * FiboTarget / 100.0; } } } 2. и функция определения отработанности паттерна //+-------------------------------------------------------------------------------------+ //| Проверка паттернов на отработку | //+-------------------------------------------------------------------------------------+ int GetPatternTarget(int total) { // ---- обозначим и инициализируем переменные и буферы int BullpatternCnt = 0; int BearpatternCnt= 0; int GetTP; int BearpatternIndex[]; int BullpatternIndex[]; int BullTPIndex[]; int BearTPIndex[]; double BullpatternTP[]; double BearpatternTP[]; ArrayResize(BullpatternIndex, total); ArrayResize(BullpatternTP, total); ArrayResize(BullTPIndex,total); ArrayResize(BearpatternIndex, total); ArrayResize(BearpatternTP, total); ArrayResize(BearTPIndex,total); FindPatterns(total, BullpatternCnt, BearpatternCnt, BullpatternIndex, BearpatternIndex, BullpatternTP, BearpatternTP, BullTPIndex, BearTPIndex, GetTP); // - 1 - == Окончание блока ============================================================= for (int i = 0; i < BullpatternCnt; i++) { if (Bid >= BullpatternTP) { GetTP = GET_TARGET; } else { GetTP = NOTGET_TARGET; } Print ("Бычий паттерн № - " + BullpatternCnt + " Свеча паттерна № - " + BullTPIndex+ " Его таргет - " +DoubleToStr(BullpatternTP,Digits)+ " Отработал ли паттерн? " + GetTP); } return(GetTP); } Принтами проверяю то ли находится, на какой свече, с каким таргетом и отработан ли паттерн относительно Bid (GetTP - возвращает 1, если отработан и -1, если нет). Собственно цель сообщения - просьба помочь реализовать кусок кода (скорей всего это будет не один цикл, а зацикленный цикл в цикле - не могу вразуметь этот вопрос - запутываюсь постоянно), в котором для каждого паттерна его таргет (BullpatternTP) сравнивался с хаем каждой последующей свечи начиная со свечи после формирования паттерна (BullpatternIndex -1) до тех пор пока хай не будет больше таргета, как только это случилось, паттерна перекрашивается или удаляется из массива - не суть. Буду очень признателен

Scriptong: evbut пишет: Игорь, предложенный вами вариант сравнения элементов массивов таргетов с Bid как бы не совсем то, чтобы хотелось видеть Согласен. Если речь идет об истории, то Bid не поможет. Нужно запоминать паттерн и затем, по экстремумам последующих свечей, делать выводы о его отработке. Это более сложная задача. Подобную задачу я как раз решал в индикаторе Всплеск и полка. Для этого организовывался массив зарегистрированных паттернов (см. переменную g_patterns), который пополнялся при обнаружении нового паттерна (функция AddPatternToArray) и уменьшался в момент пробоя уровня полки или истечения паттерна (функция ProcessPatterns). Таким образом, необходимо разделить два этих процесса: регистрацию паттернов и отслеживание их отработки.

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

Scriptong: evbut пишет: Вы пошутник, батенька )))) я тут циклы освоить не могу, а вы мне предлагаете разобраться в структурах и переделать индикатор через них Дело в том, что, на мой взгляд, наиболее просто поставленная Вами задача решается именно так, как я показал. Если убрать из решения структуры, то принцип работы будет несколько затуманен, решение будет сложнее. Поэтому тут могу советовать только продвинуться в направлении массивов и структур. Если есть желание с Вашей стороны продвинуться, то можете открыть отдельную ветку, в которой задать мне вопросы по проблемам, с которыми не смогли освоить сами. Но сразу оговорюсь - основная работа по обучению будет на Вас. То есть Вы сами начинаете разбираться в проблеме, а только потом, когда что-то непонятно, задаете вопрос. Конкретный вопрос, а не общий. evbut пишет: Если серьезно - то мысль отличная - сравнивать отработку не по хаям каждой последующей свечи, а по фракталам. В SplashAndShelf нет проверки отработки паттерна по фракталам. Там паттерн строится по фракталам. Срабатывание паттерна - по экстремумам свечей, т. е. так, как я и советую Вам с Price Action. Если делать проверку отработки по фракталам, то получим дополнительное запаздывание в два бара, т. к. в момент пробоя еще неизвестно, будет тут фрактал, или нет. Запаздывание мешает уже на этапе регистрации паттерна, но тут уже ничего не поделаешь. Если добавлять сюда запаздывание по пробою, то картинка совсем грустная выйдет.

evbut: Спасибо за развернутый ответ профессионала. Конечно вам видней как проще решить поставленную задачу. Не знаю насколько способностей хватит, чтобы, имея вообще поверхностное знание программирования, освоить и структуры. Пока желание получить решение моей задачи не пропало, то будем шагать в эту сторону. Глядишь и полностью индикатор перепешу)))

Scriptong: evbut пишет: Конечно вам видней как проще решить поставленную задачу. У одной и той же задачи, чаще всего, существует несколько решений. Но для конкретного человека такое множество решений не всегда доступно. Поэтому я говорю чисто "со своей колокольни". evbut пишет: Не знаю насколько способностей хватит, чтобы, имея вообще поверхностное знание программирования, освоить и структуры Так может просто подтянуть уровень знаний? Ведь в этом деле основной камень преткновения - желание. Если желание получения знаний есть, то это 90% гарантии того, что все у Вас получится. Большинство программистов MQL4 именно так и учились. Я в том числе.

evbut: Так может просто подтянуть уровень знаний? Как видите на ваших примерах и статьях повышаю навыки, коль уже за структуры начали говорить )) В качестве наглядного пособия почитаю код индикатора "Всплес и полка". А вот учебного что-нить можете подсказать, документация и учебник mql4 слабоват на эту тему - там про классы больше.

Scriptong: evbut пишет: коль уже за структуры начали говорить Структуры - это не очень сложно, если Вы уже осилили понятие "Типы данных". Ведь структура - это пользовательский тип данных. Довольно неплохо описано вот здесь. Не смотрите, что там для C++. Ведь MQL4 - это и есть модифицированный для торговли C++. То есть примеры из статьи можно применять непосредственно в MQL4.

evbut: Scriptong пишет: Структуры - это не очень сложно, если Вы уже осилили понятие "Типы данных". С этой штукой знаком конечно. Спасибо, обязательно почитаю и по ссылке и так, что сам найду

evbut:

evbut: День добрый, Игорь... начитался статей и ваших кодов. Кстати говоря, индикатор Всплеск и полка не что иное как один из Сложных паттернов ПрайсЭкшен в вашей статье. В общем кое-что у меня получается переделать в индикаторе через структуры. Похвастаюсь куском кода, который заполняет массив структуры паттернов: //+-----------------------------------------------------------------------------+ //| Сбор данных | //+-----------------------------------------------------------------------------+ void GetData(int index, int& startBar, int &type, int &patternName) { //- 1 - == Определим тип найденного паттерна по направлению ===================== if(IsBullsPPRPattern(index) || IsBUOVBPattern(index) || IsBullsRailsPattern(index) || IsBullsTOKPattern(index)) type = BULL_TYPE; if(IsBearsPPRPattern(index) || IsBearsRailsPattern(index) || IsBearsTOKPattern(index) || IsBEOVBPattern(index)) type = BEAR_TYPE; //- 1 - == Конец =============================================================== //- 2 - == Определим левую границу найденного паттерна ========================= if(IsBullsPPRPattern(index) || IsBearsPPRPattern(index) || IsBullsTOKPattern(index) || IsBearsTOKPattern(index)) startBar = index+2; if(IsBUOVBPattern(index) || IsBEOVBPattern(index)|| IsBearsRailsPattern(index) || IsBullsRailsPattern(index)) startBar = index+1; //- 2 - == Конец =============================================================== //- 3 - == Ообозначим паттерн по названию======================================= if(IsBullsRailsPattern(index) || IsBearsRailsPattern(index)) patternName = RAILS_INDEX; if(IsBUOVBPattern(index) || IsBEOVBPattern(index)) patternName = OVB_INDEX; if(IsBullsPPRPattern(index)|| IsBearsPPRPattern(index)) patternName = PPR_INDEX; if(IsBullsTOKPattern(index) || IsBearsTOKPattern(index)) patternName = TOK_INDEX; //- 3 - == Конец =============================================================== } //+-----------------------------------------------------------------------------+ //| Заполнение массива и отрисовка паттернов | //+-----------------------------------------------------------------------------+ 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; double BuyTP = ND(lowPrice + patternHeight * FiboTarget / 100.0); double SellTP = ND(highPrice - patternHeight * FiboTarget / 100.0); // string nameofpattern = PatternName(patternName); int patternArray = ArraySize(g_patterns); if(patternDir !=0) { if( ArrayResize(g_patterns, patternArray+1, ARRAY_RESERVE_SIZE) < 0) { Alert(WindowExpertName(),(g_isRussianLang)? ": Недостаточно памяти для продолжения работы программы. Индикатор отключен.": ": Not enough memory to continue work the program. Indicator is turned off."); } g_patterns[patternArray].patternType = patternDir; g_patterns[patternArray].patternName = patternName; g_patterns[patternArray].leftBarIndex = startBar; g_patterns[patternArray].rightBarIndex = index; g_patterns[patternArray].patternHighPrice = highPrice; g_patterns[patternArray].patternLowPrice = lowPrice; if(patternDir == BEAR_TYPE) g_patterns[patternArray].patternColor = RegcolorBears; else g_patterns[patternArray].patternColor = RegcolorBulls; if(patternDir == BULL_TYPE) g_patterns[patternArray].patternTarget = BuyTP; else g_patterns[patternArray].patternTarget = SellTP; //Проверка паттерна на отработку таргета if(IsShowWorked) 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.patternColor = WorkColor; } } 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.patternColor = WorkColor; } } } // === Отрисуем паттерны =========== if(!IsShowALLPatterns) DeleteAnyPattern(index, index+2); // Удаление перекрытых паттернов if(IsRectangleShow) { string name = GetUniqueID(g_patterns[patternArray], FIRST_PART); /*string name = GetObjectName(g_patterns[patternArray].rightBarIndex, g_patterns[patternArray].patternType, FIRST_PART);// Имя объекта паттерна*/ ShowRectangle(name, Time[g_patterns[patternArray].leftBarIndex], g_patterns[patternArray].patternLowPrice, Time[g_patterns[patternArray].rightBarIndex],g_patterns[patternArray].patternHighPrice, "",g_patterns[patternArray].patternColor); } /*string name = GetObjectName(g_patterns[patternArray].rightBarIndex, g_patterns[patternArray].patternType, SECOND_PART);// Имя объекта паттерна */ string name = GetUniqueID(g_patterns[patternArray], SECOND_PART); ShowTarget(name, Time[g_patterns[patternArray].leftBarIndex], g_patterns[patternArray].patternTarget, Time[g_patterns[patternArray].rightBarIndex], g_patterns[patternArray].patternTarget, "",g_patterns[patternArray].patternColor); Print(" Pattetn Count " +string(patternArray) + // " Pattern Start Bar " + g_patterns[patternArray].leftBarIndex + " Pattern End Bar " + string(g_patterns[patternArray].rightBarIndex) + " Pattern Type " + EnumToString(g_patterns[patternArray].patternType) + " Pattern Name " + EnumToString(g_patterns[patternArray].patternName)); // " Pattern Color " + g_patterns[patternArray].patternColor + // " Pattern High " + g_patterns[patternArray].patternHighPrice + // " Pattern Target " + g_patterns[patternArray].patternTarget); } } И рисует и перерисовывает, если таргет паттерна пробит - голову сломал об эту логику )) Пока это все в одной функции находится, но на 90% работает... Теперь осталось только сделать, чтоб перекрывающиеся паттерны не отображались.

Scriptong: evbut пишет: Теперь осталось только сделать, чтоб перекрывающиеся паттерны не отображались. Достаточно сложная задача. Чтобы ее решить, нужно организовать запоминание расположения паттернов. В итоге при отображении очередного паттерна нужно проверить, накладывается ли этот паттерн на какой-либо другой. Это еще несложно. Сложность в том, чтобы разработать правило, позволяющее наиболее оптимальным образом отобразить оба эти паттерна или только один из них. Для каждой подобной задачи приходится искать сугубо ее, индивидуальное, решение. К примеру, в показанном Вами случае нужно не отображать тот паттерн, который полностью перекрывается следующим паттерном. Правда, возникает вопрос: а как же указать пользователю, что имеет место наложение паттернов? В компьютерных играх такая ситуация разрешается путем отображения специального значка, указывающего на наложение элементов. Затем, если игрок выделяет такой элемент, то выводится меню, показывающее все наложенные в этом месте элементы. При помощи такого меню можно получить доступ к каждому элементу. В случае с МТ подобная возможность может быть реализована. Первый подход к этому я сделал в индикаторе Скрытые гэпы. Правда, не скажу, что результатом я доволен на 100%.

evbut: Scriptong пишет: Сложность в том, чтобы разработать правило, позволяющее наиболее оптимальным образом отобразить оба эти паттерна или только один из них. Для каждой подобной задачи приходится искать сугубо ее, индивидуальное, решение. Как, видите, каждый паттерн отображается не только в виде прямоугольника, но и черточки таргета. В случае реализации полного набора паттернов прайс экшен (В вашем индикаторе их 11 штук) задача вами решалась посредством приоритетности (силе) того или иного паттерна. Мне нужны только 3 из них (хотя не сложно добавить и другие, как оказалось) по этому проблема наложения актуальна лишь для прямоугольников, черточки не так сильно загромождают график, поэтому, как вариант, полагаю, достаточно будет реализовать удаление или не отображение лишь прямоугольника, а для черточки, если ее паттерн еще актуальный, но перекрывается с соседним, можно добавить описание, что паттерн еще актуальный. Кстати, это момент (актуальный паттерн или нет) стоит добавить вообще ко всем паттернам. Еще вариант - возможность заливки прямоугольника на выбор, что кстати реализовано у меня, но он как бы неплохо смотрится при малом количестве паттернов (см. рисунок - рыжие - неактуальные паттерны, голубой - актуальные), а если паттернов будет 11, то это не спасет - будет чахорда линий от прямоугольников на свечах... Также можно фильтровать паттерны через ATR, если высота паттерна меньше ATR(24), то не отображается паттерн и кстати. это было бы логично, потому как зачастую чахорда происходит при низкой волатильности.

Scriptong: evbut пишет: как вариант, полагаю, достаточно будет реализовать удаление или не отображение лишь прямоугольника Согласен. Тоже вариант. Но даже для него в любом случае нужно вести базу данных об отображенных паттернах. Тогда перед отображением нового прямоугольника нужно будет пройтись по всей базе и найти все паттерны, которые находятся в координатах для вывода нового паттерна. Такие паттерны удаляются физически с графика, а затем - из базы данных. Новый паттерн вносится в базу данных.



полная версия страницы