Очень странный глюк тестера MT4

 

Программирую уже 15-й год на языке MQL4. До последнего билда терминала с таким ранее не сталкивался. Итак ситуация тестера.

В рынке 3 ордера: один лонг и два шорта. На скрине это видно


Мне нужны цены и лоты шортов. Пишу цикл, перебирающий ордера:

for(int i=OrdersTotal()-1;i>=0;i--){
    if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			SelectError(i);
			Print("==================== ",FunctionName," ====================");
			return(-1);
		}
    else{
			if(Type=="SELL"){
				SchOrd=SchSell(MAGIC);
				Print("В раздел SELL зашли, SchOrd = ",SchOrd," Выбран ордер № ",i," Тип ордера = ",OrderType());
				if(OrderType()==OP_SELL){ 	
					Print("Тип ордера = ",OP_SELL," SchOrd = ",SchOrd); 

Тут идёт сравнение значения переменной Type со строковым значением "SELL". Значение Type подаётся на вход функции, внутри которой выполняется этот код. Далее в журнал отписывается результат принта:

Как видим, в переменной SchOrd содержится верное значение - у меня действительно 2 шортовых ордера. Всего ордеров три. В списке ордеров они идут под номерами от нуля до двух. Всё нормально. НО! функция OrderType() возвращает значение = 0 как при выборе Бай-ордера (что правильно), так и при выборе Селл-ордера. А вот это не верно, ибо в справке читаем (и это всегда работало):

// OP_BUY        0   Покупка 
// OP_SELL       1   Продажа 
// OP_BUYLIMIT   2   Отложенный ордер BUY LIMIT 
// OP_SELLLIMIT  3   Отложенный ордер SELL LIMIT 
// OP_BUYSTOP    4   Отложенный ордер BUY STOP 
// OP_SELLSTOP   5   Отложенный ордер SELL STOP

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

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

Что мне с глюком-то делать? Я конечно попробую инициализировать счётчик шортов ПЕРЕД циклом перебора ордеров. Но мне он в цикле нужен!

 

Понимаете, в цикле выбирается очередной ордер и это шорт. А Функция OrderType() возвращает значение, равное лонгу. В результате принт вот этот не выполняется вообще

Print("Тип ордера = ",OP_SELL," SchOrd = ",SchOrd); 
 

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

Косяк, однако.

Но это приводит нас к вопросу: Язык MQL4 поддерживает вызов Рекурсивных функций? Разработчики, поясните пожалуйста, ну так, хотя бы для ясности.

 

Откуда бы не был вызван OrderSelect(), он выбирает ордер. И до следующего OrderSelect() этот выбор не изменится.

"Это не баг, это фича" (с)

 
Andrey Khatimlianskii:

Откуда бы не был вызван OrderSelect(), он выбирает ордер. И до следующего OrderSelect() этот выбор не изменится.

"Это не баг, это фича" (с)

Речь не об этом.  Вникните.

 
Всё правильно работает, что выбрали функцией, то и должны получать. 
 
Vitaly Murlenko:

Что мне с глюком-то делать? Я конечно попробую инициализировать счётчик шортов ПЕРЕД циклом перебора ордеров. Но мне он в цикле нужен!

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


И вообще, никогда не полагайтесь на недокументированные возможности и не будет неожиданного поведения у программ.

 
Vitaly Murlenko:

Речь не об этом.  Вникните.

Да вот как раз об этом и речь. Придется вам вникать. ))

Никакого выделения памяти для каких-то блоков программы при вызове OrderSelect() не существует. Блоки программы вообще существуют только у нас в голове. Для компилятора все это единый код. Раз вызвали OrderSelect(), то получите данные для всего кода, а не для  каких-то отдельных его блоков, о существовании которых знает только программист и никто более.

 
Vitaly Murlenko:

Программирую уже 15-й год на языке MQL4. 

И за 15 лет впервые столкнулись с такой ситуацией? Везунчик, однако. Люди на первом году с этим сталкиваются и запоминают на всю оставшуюся жизнь.

А сколько тем создано по этому вопросу… аж страшно сказать…

 
Ihor Herasko:

Да вот как раз об этом и речь. Придется вам вникать. ))

Никакого выделения памяти для каких-то блоков программы при вызове OrderSelect() не существует. Блоки программы вообще существуют только у нас в голове. Для компилятора все это единый код. Раз вызвали OrderSelect(), то получите данные для всего кода, а не для  каких-то отдельных его блоков, о существовании которых знает только программист и никто более.

Речь шла не о выделении памяти для блоков программы, речь шла о том, что подпрограмма не должна вмешиваться в работу основной программы. У меня цикл основного кода вызывает другой цикл подпрограммы, которая лежит в библиотеке (читай, совершенно в другом файле). Из цикла советника вызывается цикл, расположенный в подпрограмме. Подпрограмма не является блоком основной программы!!! Она ОТДЕЛЬНАЯ штука. Можно вызывать, можно не вызывать.

Вот представьте ситуацию, Вы написали аудиоплеер. Он просто воспроизводит музыку. Но Вам понадобилось воткнуть в него кнопку, которая считывает некое значение трека и передаёт его в одну из API-функций Windows-а. Там происходит обработка введённых данных и возврат в виде обычного текстового сообщения с результатами обработки. Эта апи-функция будет ПОДПРОГРАААМОЙ для Вашего плеера. И она должна выполняться в ОТДЕЛЬНОМ сегменте оперативной памяти. И вот эта подпрограмма взяла да и ни с того ни с сего вмешалась в основную программу - взяла и до максимума увеличила Вам громкость воспроизведения. А у Вас глубокая ночь и домашние спят. Это же ненормально, если Вы не запрашивали увеличение громкости.

 
Vitaly Murlenko:

 Она ОТДЕЛЬНАЯ штука. Можно вызывать, можно не вызывать.

Вы точно все это время занимались изучением языка?

ОНА - это терминал и MQL-программа, они действительно "отдельные штуки" - ордера в терминале кстати, а MQL- запрашивает данные об ордерах из терминала

Кимовские функции посмотрите хоть сейчас, многие из них так и устроены - в одной функции происходит выбор необходимого ордера через OrderSelect() - и вызов другой функции, которая производит манипуляции с предварительно выбранным ордером


если у Вас каждая функция выполняет отдельно отбор необходимых ордеров по Вашему критерию- или передавайте тикет ордера или оптимизируйте вызовы  OrderSelect() - другого не дано

в МТ4 можно очень часто перебирать ордера используя  OrderSelect(i, SELECT_BY_POS )  - производительность от этого не страдает, в МТ5 лучше оптимизировать вызовы  OrderSelect(), но с учетом что МТ5 намного быстрее 4-ки, многие решения и так не плохо работают

Причина обращения: