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



Сообщение: 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 [только новые]





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

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