Как ускорить работу получения списка закрытых ордеров? - страница 2

 
Artyom Trishkin:
Всё ищется по истории. У каждого связанного ордера есть тикет на его родителя или потомка.
Я не у компа чтобы показать кодом. Но задачка лёгкая.
Просто напишите на бумажке тикеты исторических ордеров и тикеты, прописанные в их коментариях. И сразу увидите связь.

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


По скрину.
Ордер 376295094 был открыт объемом 0.50 и закрылся частично. Образовал ордер 376295189 и прописал это у себя в комментарии.
Ордер 376295189 закрылся частично объемом 0.05 и образовал ордер 376300257 (этот тикет прописан в комментарии и у родительского, и у дочернего ордера в комментарии). Этот ордер дальше был частично закрыт лотом 0.02  и образовал ордер 376303649.

Моделируем ситуацию.  У меня в открытых ордерах болтается ордер 376303649, мне нужно по этому тикету найти ордер 376295094 и посчитать число его закрытий.
В комментарии открытого ордера (376303649) прописано from #376300257. Выбираю этот ордер 376300257. У него комментарий 376303649. Круг замкнулся.
Теперь чтобы решить задачу, нужно перебором найти ордер, у которого в комментарии будет прописан тикет 376300257. Что все равно требует перебора всех ордеров. Или я чего-то не улавливаю?

 
Artyom Kuraev:

 Что все равно требует перебора всех ордеров. Или я чего-то не улавливаю?

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

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

Единственный нюанс, который в МТ4 не решается программно - это доступ ко всей истории. Если пользователь выберет отображение неполной истории счета, то эксперт тоже будет оперировать неполной историей. Причем программно определить отсутствие полной истории счета никак не удастся. В этом случае остается лишь сообщать и постоянно напоминать пользователю о необходимости поддержки истории счета в состоянии "Вся история".

 
Ihor Herasko:

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

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

Единственный нюанс, который в МТ4 не решается программно - это доступ ко всей истории. Если пользователь выберет отображение неполной истории счета, то эксперт тоже будет оперировать неполной историей. Причем программно определить отсутствие полной истории счета никак не удастся. В этом случае остается лишь сообщать и постоянно напоминать пользователю о необходимости поддержки истории счета в состоянии "Вся история".

Игорь, а для добавления истории в список достаточно провести цикл от OrdersHistoryTotal() до первой совпадающей строчки? Просто читал, что бывают сбои в последовательности этого списка.
 
Artyom Kuraev:
Я буду благодарен, если мы до конца разберем ситуацию и вы мне поможете понять, что я не прав, но мне кажется вы ошибаетесь.


По скрину.
Ордер 376295094 был открыт объемом 0.50 и закрылся частично. Образовал ордер 376295189 и прописал это у себя в комментарии.
Ордер 376295189 закрылся частично объемом 0.05 и образовал ордер 376300257 (этот тикет прописан в комментарии и у родительского, и у дочернего ордера в комментарии). Этот ордер дальше был частично закрыт лотом 0.02  и образовал ордер 376303649.

Моделируем ситуацию.  У меня в открытых ордерах болтается ордер 376303649, мне нужно по этому тикету найти ордер 376295094 и посчитать число его закрытий.
В комментарии открытого ордера (376303649) прописано from #376300257. Выбираю этот ордер 376300257. У него комментарий 376303649. Круг замкнулся.
Теперь чтобы решить задачу, нужно перебором найти ордер, у которого в комментарии будет прописан тикет 376300257. Что все равно требует перебора всех ордеров. Или я чего-то не улавливаю?

1:to#2 --> 2:to#3 --> 3:to#4 --> 4:from#3

  1. Видим открытый 4. Нужно найти его изначального родителя.
  2. Смотрим его комментарий, если нету "#from", то он сам и есть потенциальный родитель.
  3. Если есть, то ...
  4. Берём из комментария "from#3", записываем этот тикет в родители, а 4 как потомка
  5. Смотрим список исторических ордеров,
  6. Если нет в комментариях "to#4", значит 3 - родитель, иначе 3 - потомок от кого-то ещё
  7. находим "to#ТикетПотомка", переписываем родителя на тикет этого найденного ордера и идём на п5.

Вродь ничего не забыл...

И, да, верно Игорь вам написал - не нужно историю дёргать на каждом тике. Ведь поднятие и получение полного торгового окружения - весьма и весьма дорогая операция.

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

 
Artyom Kuraev:

Добрый день, уважаемые программисты.

Столкнулся с такой задачей. Пишу советник, который должен частично закрывать сделку несколько раз при выполнении определенных условий. Для того, чтобы проверить, выполнены ли условия для следующего частичного закрытия, нужно для начала узнать, сколько раз от исходного ордера уже отщипывали кусочек лота. И это можно сделать только путем перебора всех закрытых ордеров и проверки времени открытия и направления сделки и цены открытия (все остальные параметры могут быть изменены советником, а комментарий меняется автоматически при частичном закрытии, поэтому его использовать его тоже не вариант). Вести журнал сделок с сохранением информации на жесткий диск не хочется (вряд ли выиграю по скорости - нужно файл открыть, прочитать, исправить, сохранить, закрыть).
При этом задача в том, чтобы советник был стабилен при сбое терминала, поэтому список закрытых ордеров получаю на каждом тике, но нужно решить вопрос быстродействия программы. Советник планируется запускать на нескольких парах одновременно и из-за мелкого таймфрейма список сделок быстро растет. Но из-за того, что эта же стратегия может применяться на старших таймфреймах, список отображаемой истории нужно держать хотя бы за месяц.
Так как проверку условий нужно совершать по каждому открытому на данный момент ордеру (а их может быть несколько), копирую информацию в память программы, записывая в структуру, чтобы потом осуществлять перебор в ней.
В принципе, чтобы не копировать весь список открытых ордеров (я фильтрую и собираю в массив структур только те ордеры, которые могут быть интересны самой программе в том или ином месте алгоритма), я думаю, что можно было бы узнать дату самого раннего открытого ордера из интересующих и не копировать историю младше конкретного числа. Но на практике этот подход может дать сбой, если пользователь в списке истории ордеров поставит сортировку, например, по валютной паре, объему или типу.

Больше не могу придумать никаких вариантов.

Может кто сталкивался с подобной задачей? Подскажите, как можно еще решить вопрос производительности?

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

то есть ваше решение "хранить историю в своих структурах" правильное. А вот запрашивать её на каждый тик - увы нет. Ответ содержится в вашем-же вопросе (хороший вопрос, это уже половина ответа).
На тике,или просто периодично, можно смотреть что изменилось и только тогда синхронизоваться с сервером.
 
ограничить глубину истории например одним днём, в настройках терминала, по идее должно помочь ускорится, замедление происходит от количества ордеров в истории, чем их больше тем медленнее идёт обработка
 
Artyom Trishkin:

1:to#2 --> 2:to#3 --> 3:to#4 --> 4:from#3

  1. Видим открытый 4. Нужно найти его изначального родителя.
  2. Смотрим его комментарий, если нету "#from", то он сам и есть потенциальный родитель.
  3. Если есть, то ...
  4. Берём из комментария "from#3", записываем этот тикет в родители, а 4 как потомка
  5. Смотрим список исторических ордеров,
  6. Если нет в комментариях "to#4", значит 3 - родитель, иначе 3 - потомок от кого-то ещё
  7. находим "to#ТикетПотомка", переписываем родителя на тикет этого найденного ордера и идём на п5.

Вродь ничего не забыл...

И, да, верно Игорь вам написал - не нужно историю дёргать на каждом тике. Ведь поднятие и получение полного торгового окружения - весьма и весьма дорогая операция.

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

Артем, так у меня задача как раз была обойтись без обращения к списку истории. В  MQL4 единственный способ обратиться к истории - это пробежаться про нему списком от 0 до OrdersHistoryTotal()-1, выбрать каждый потенциально подходящий и сверить комментарий (об этом я писал с первого своего сообщения - это равнозначно сверке по цене и времени открытия). Или пункт 5 в Вашем списке возможен в MQL4 с иной реализацией?

А вот идея загружать историю только один раз, а потом обновлять ее по мере поступления новой информации мне очень понравилась. Благодарю.

 

Просматриваем ордера от OrdersHistoryTotal()-1 до N   а дальше устаревшая история. По мере работы N корректируем в сторону увеличения

 
Artyom Kuraev:

Артем, так у меня задача как раз была обойтись без обращения к списку истории. В  MQL4 единственный способ обратиться к истории - это пробежаться про нему списком от 0 до OrdersHistoryTotal()-1, выбрать каждый потенциально подходящий и сверить комментарий (об этом я писал с первого своего сообщения - это равнозначно сверке по цене и времени открытия). Или пункт 5 в Вашем списке возможен в MQL4 с иной реализацией?

А вот идея загружать историю только один раз, а потом обновлять ее по мере поступления новой информации мне очень понравилась. Благодарю.

Пункт 5 - это работа со своим списком, который один раз на каждом изменении сохраняется.

 

Создавать дубликат всей истории в каждом экземпляре бота нет необходимости, раз уж вам так дороги ресурсы. Достаточно запомнить тикет родителя при его открытии и каждого наследника находить через OrderSelect + OrderComment, без прочёсывания OrdersHistoryTotal. Хранить инфо всей цепочки или только заменять тикет более актуальным - по вкусу

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