расхождение между AccountNumber() и OrdersHistoryTotal(), OrdersTotal() и OrderSelect(i, SELECT_BY_POSE, MODE_HISTORY)

 

Уважаемые! Буду рад Вашим комментариям, а в особенности мнению разработчиков!

Как можно объяснить то, что OrderSelect(i, SELECT_BY_POSE, MODE_HISTORY) выберает тикет, принадлежащий аккаунту, который был залогинен до текущего аккаунта, хотя, ещё до выборки тикета, было проверено, что AccountNumber() возвращает номер аккаунта равного текущему?

..тоже самое случается и с OrdersHistoryTotal() и OrdersTotal() - иногда они возвращают кол-во закрытых/открытых ордеров, которое соответствует аккаунту, который был залогинен до текущего.

Стоит уточнить, что это происходит далеко не всегда, примерно 1 раз из 100 логинов. Что в принципе усложняет процесс дебаггинга. Кстати я постоянно мониторю состояние GetLastError() - никаких ошибок во время и до расхождений не зафиксировано.

Также стоит уточнить, что сам процесс логина Аккаунтов автоматизирован, т.е. например в моём случае функции OrdersHistoryTotal(), OrdersTotal() и OrderSelect() вызываются сразу после успешного логина (который определяется следующим условием - if( IsConnected() && AccountNumber() == xxxxxx )). Не использую sleep'ы.

Буду рад Вашим комментариям, в особенности от тех, кто знает как в действительности работают эти функции и как можно предотвратить расхождения в возвращаемых ими результатах..

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

Заранее Спасибо!

 

Интересно... Надо будет учесть в будущем.

Вопрос: Вы процедуры if( IsConnected() && AccountNumber() == xxxxxx )) и перебор Ордеров происходит в init() или в start() ?

 
rlx:

Интересно... Надо будет учесть в будущем.

Вопрос: Вы процедуры if( IsConnected() && AccountNumber() == xxxxxx )) и перебор Ордеров происходит в init() или в start() ?


в start()
 

Для проверки, поставил sleep(12000) после if( IsConnected() && AccountNumber() == xxxxxx )) - и баг уже не случается. Но это не решение:)

Насколько я понимаю после смены аккаунта, у терминала уходит время на обновление каких-то данных/внутренних переменных (помимо возвращаемого от AccountNumber()!!), от которых зависит результат OrderSelect(), OrdersHistoryTotal() и OrdersTotal()..

Вопрос какие ещё проверки мне следует осуществить помимо (IsConnected() && AccountNumber() == xxxxxx), чтобы удостовериться, что всё готово для работы с аккаунтом?!

Уважаемые разработчики, отзовитесь!

 

Думается можно проверять по Магическим номерам ордеров.

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

(только нужно чтобы был хотя бы один ордер)

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

(хотя если АккаунтНамбер изменяется, то и АккаунтБаланс изменится)

Поэтому безопасней будет проверять ордера, т.к. работать то будем с ордерами.

 

Скорее всего баг терминала после переключения, когда история по текущему счету еще подгружена.

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

 
rlx:

Думается можно проверять по Магическим номерам ордеров.

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

не подходит, т.к. ордера открываются/закрываются не мною.

rlx:

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

не подходит, т.к. во-первых баланс может измениться до логина, а во-вторых как Вы сами и подметили, скорее всего AccountBalance() работает аналогично AccountNumber()..

TheXpert:

Скорее всего баг терминала после переключения, когда история по текущему счету еще подгружена.

В том то и дело, что так оно и есть:) Но ведь должен быть какой-то способ, с помощью которого можно определить, подгруженна история текущего аккаунта, или предыдущего. Или хотя-бы способ, очищяющий какую-либо подгруженную историю перед следующим логином, тогда после логина достаточно было бы проверить if(OrdersHistoryTotal() > 0)

 
Необходимо подождать, пока в терминал подгрузятся данные по новому счету. Посмотрите также вариант в моем индикаторе Specification

/поправил ссылку - granit77/

 
Rosh:
Необходимо подождать, пока в терминал подгрузятся данные по новому счету. Посмотрите также вариант в моем индикаторе Specification

/поправил ссылку - granit77/

Благодарю за ответ. Ждать пробывал, аж 12 секунд, но на второй день бесперебойного тестинга в реальных условиях было зафиксировано положение, при котором функции AccountNumber() и OrderSelect() возвращали данные, относящиеся к разным аккаунтам, несмотря на то, что скрипт прождал 12 секунд после успешного логина. На тот момент стало понятно, что на "ожидание" полагаться нельзя.

Тем не менее, по совету знакомого, мне удалось решить проблему используя следующую схему:

После успешного логина (на данном этапе успешный логин определяется по значению AccountNumber()), проверяется номер первого закрытого тикета + время его закрытия (полученные от OrderSelect(0, SELECT_BY_POS, MODE_HISTORY)) со значением записанным в бд/файле по данному аккаунту, до тех пор, пока значения не будут равны или же не наступит таймаут. Таким образом скрипт никогда не продолжит работу с аккаунтом, пока OrderSelect() и AccountNumber() не станут возвращять данные, относящиеся к одному и тому же аккаунту, вне зависимости от того, сколько времени у них это займёт.

Rosh, Хотелось бы знать, что объединяет и что различает функции: AccountNumber() и OrdersHistoryTotal(), OrdersTotal(), OrderSelect()? Почему они иногда по-разному обновляются? Какие ещё функции могут возвращять различные по аккаунту данные подобно этим? А также, чего следует ожидать от функции AccountCompany() - она подобна AccountNumber() или второй группе?

Заранее Спасибо!

 

Думаю, лучшее понимание даст прочтение статьи Ордерa, позиции и сделки в MetaTrader 5. Хоть система учета в платформе MetaTrader 5 отличается от предшественника, но подход к хранению и обработке информации в самом терминале очень похож:

Как терминал получает и хранит торговую информацию с сервера

Терминал хранит торговую историю в специальной собственной базе и получает только недостающую историю сделок и отработавших ордеров на торговом счете при каждом подключении к торговому серверу. Это сделано с целью экономии трафика. При закрытии клиентского терминала MetaTrader 5 или смене текущего активного счета вся история записывается на жесткий диск и считывается с него при следующем запуске терминала.

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

При потере подключения к торговому серверу терминал периодически предпринимает попытки восстановить связь. После восстановления соединения с сервером терминал запрашивает все последние изменения в торговой истории для поддержания целостности данных в собственной базе истории.

...

Клиентский терминал посылает запросы на синхронизацию собственной базы торговой истории при включении терминала, при восстановлении связи с сервером после сбоя подключения, при переключении с одного счета на другой.

...

Каждая mql5-программа получает для своей работы "слепок" торгового окружения в свой кэш. Кэш - это специальная область памяти для быстрого доступа к данным. Например, прежде чем начать обработку действующих ордеров, необходимо получить в кэш mql5-программы требуемый ордер. Вся дальнейшая работа при обращении к ордеру будет производиться с кэшированной копией ордера.

...

Важно: данные в кэше автоматически не синхронизируются с базой терминала, для поддержания актуального состояния данных в кэше необходимо явное их обновление.

Возможные последствия при неправильном использовании кэша:

  • если данные по запросу получить не удалось, то кэш будет пустой и не будет содержать необходимых данных.
  • если данные в кэше требовали обновления, но обновление не запрашивалось, то работа с такими данными может привести к непредсказуемым результатам. Например, данные о текущей позиции не были обновлены, и программа ничего не знает об открытой позиции по данному символу и о растущей величине убытка по ней.
В MQL4 нельзя программно запросить обновление торговой истории, можно только дождаться ее автоматического обновления. Если на подключаемом счете тысячи ордеров в истории, то загрузка этой истории требует времени. Вы можете ограничить торговую историю более коротким интервалом вручную.
 
Rosh:

Думаю, лучшее понимание даст прочтение статьи Ордерa, позиции и сделки в MetaTrader 5. Хоть система учета в платформе MetaTrader 5 отличается от предшественника, но подход к хранению и обработке информации в самом терминале очень похож

уважаемый Rosh,

1. Допустим, в некой вызывающей функции, мы выбираем ордер при помощи OrderSelect(), затем вызываем функцию, которая выбирает другой ордер, сохранится ли первичный выбор в вызывающей функции после возврата?

2. Передается ли выбранный ордер в вызываемую функцию неявно, то есть верно ли следующее решение

//+------------------------------------------------------------------+
void CloseAllFirstProfit() {
 int i, k=OrdersTotal()-1;
 for(i=k; i>=0; i--) 
  if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))if(OrderType()==OP_BUY||OrderType()==OP_SELL)if(OrderProfit()+OrderSwap()>0)ClosePosBySelect();
 k=OrdersTotal()-1;
 for(i=k; i>=0; i--) 
  if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))if(OrderType()==OP_BUY||OrderType()==OP_SELL)ClosePosBySelect();
}
//+------------------------------------------------------------------+
void ClosePosBySelect() {
 if (OrderType()==OP_BUY)  OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 10, CLR_NONE);
 if (OrderType()==OP_SELL) OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_ASK), 10, CLR_NONE);
}
//+------------------------------------------------------------------+

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