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



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







Сообщение: 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 час. Хитов сегодня: 1
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет