Все сведения о сделках хранятся на сервере и они никуда не исчезают после сбоя клиента. Надо код строить так, чтобы состояния считывались из доступных источников, флаги - костыли.
Все сведения о сделках хранятся на сервере и они никуда не исчезают после сбоя клиента. Надо код строить так, чтобы состояния считывались из доступных источников, флаги - костыли.
Оно конечно понятно, что нужно стремиться к минимуму флагов, но все-таки если флаги - костыли, то как бы Вы порекомендовали без них реализовать такую стратегию:
имеется перерисовывающийся индикатор, который рисует канал из трех линий - верхняя, средняя и нижняя. И мы должны выполнять стратегию А с того момента, как цена уходит вниз нижнего канала и до тех пор, пока не пробьет вверх среднюю линию, и, соответственно, стратегию Б с того момента, как цена уходит вверх верхнего канала до момента, как цена не пробьет вниз уровень средней линии. Подчеркну - советник перерисовывающийся. Реализовать такую стратегию без флагов я не представляю возможным. Поделитесь, пожалуйста, опытом, как это можно сделать без флагов?
И сам вопрос по сохранению значений флагов для меня остался актуальным.
Оно конечно понятно, что нужно стремиться к минимуму флагов, но все-таки если флаги - костыли, то как быВы порекомендовали без них реализовать такую стратегию:
имеетсяперерисовывающийся индикатор, который рисует канал из трех линий -верхняя, средняя и нижняя. И мы должны выполнять стратегию А с тогомомента, как цена уходит вниз нижнего канала и до тех пор, пока непробьет вверх среднюю линию, и, соответственно, стратегию Б с тогомомента, как цена уходит вверх верхнего канала до момента, как цена непробьет вниз уровень средней линии. Подчеркну - советникперерисовывающийся. Реализовать такую стратегию без флагов я не представляю возможным. Поделитесь, пожалуйста, опытом, как это можно сделать без флагов?
И сам вопрос по сохранению значений флагов для меня остался актуальным.
...Поделитесь опытом, кто как решает подобные проблемы?
Насколько проблемы подобны, не знаю. Я ловлю изменение комплекта последних тиков по 25 парам с опросом каждые 16 миллисекунд, сейчас работает такой код выдачи строки изменений S в файл (iErr извлекает последнюю ошибку и сбрасывает соответствующую системную переменную в ноль), работало это и для 60 терминалов без ощутимых последствий для процессоров и дисков, реально ведь идет обмен с памятью (не с магнитными пластинами):
k=StringLen(S); if (k!=0) { FileWriteString(fiRes, S, k); k = iErr(); // FileFlush(fiRes); 25.05.2014 узнал, что FileFlush работает дольше 25 мс. А Close,Open,Seek исполняются 0.1 мс FileClose(fiRes); k1=iErr(); // Закрываем файл тиков, данные ушли в буфер контроллера диска for (kFi=0;kFi<=10;kFi++) { // пытаемся открыть 10 раз с шагом 0.05 сек fiRes = FileOpen(ResFName, FILE_BIN|FILE_READ|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ,0,CP_ACP); // если не было, создаст k1=iErr(); if (fiRes>=0) break; else Sleep (50); } if (fiRes<1) {ToProt(StringConcatenate ("^99 Не открывается файл ",ResFName," для записи, err=",k1)); return;} FileSeek(fiRes,0,SEEK_END); k1=iErr(); // В конец файла // Новые тики записаны, размер файла изменился, он снова открыт .......
Влад, это опять-таки идет запись в файл.
А что касается флагов - ведь по сути, любая переменная класса памяти static или переменная, объявленная на глобальном уровне mql-программы является флагом, так как сохраняет в себя то, что было раньше и передает на новую итерацию.
И при этом без статической переменной невозможно корректно обнаружить новый бар (по крайней мере, я таких функций не встречал), но ведь если во время текущего бара произойдет сбой и программа перезапустится, она вновь обнаружит ""новый" бар. Таким образом получается, что для надежной работы программы нам необходимо все static переменные и переменные, объявленные на глобальном уровне программы куда-то скидывать, либо писать такой код, чтобы абсолютно каждую переменную на каждом тике можно было вычислить "с нуля". Но как этого можно достичь?
Влад, это опять-таки идет запись в файл.
А что касается флагов - ведь по сути, любая переменная класса памяти static или переменная, объявленная на глобальном уровне mql-программы является флагом, так как сохраняет в себя то, что было раньше и передает на новую итерацию.
И при этом без статической переменной невозможно корректно обнаружить новый бар (по крайней мере, я таких функций не встречал), но ведь если во время текущего бара произойдет сбой и программа перезапустится, она вновь обнаружит ""новый" бар. Таким образом получается, что для надежной работы программы нам необходимо все static переменные и переменные, объявленные на глобальном уровне программы куда-то скидывать, либо писать такой код, чтобы абсолютно каждую переменную на каждом тике можно было вычислить "с нуля". Но как этого можно достичь?
Говоря о сбоях, надо ограничить их круг. Пока что я понял, что речь идет о ситуациях, когда прежнее содержимое памяти исчезает. Так естественно и сохранять его на диске. Однако сам по себе советник валиться не должен, это Ваша забота. Случаи внешнего вмешательства возможны, случайно закрыли терминал крестиком в верхнем правом углу и др. Бывают и более серъезные причины. По моему опыту, самая частая - отказ электропитания.
Насколько я догадываюсь, в Ваших ТЗ нет требования обеспечить взрывозащищенную работу советника. Защищать надо не от взрыва газового баллона в соседней комнате, а от отказа электропитания. В первую очередь установкой устройства бесперебойного питания. И, например, запуском скидывания всего нужного на диск по сигналу от этого устройства о том, что емкость аккумулятор скоро будет исчерпана. Или жестче, как Вы пишете, записью на диск на каждый тик. Даже в отсутствие бесперебойника данные, переданные в буфер контроллера диска, успеют при отказе питания записаться на магнитные пластины (для этого используются накопленные механическая энергия вращения и электрическая энергия на обкладках конденсаторов).
Общий подход к ответственному хранению данных хорошо развит в универсальных системах управления базами данных (СУБД). Непрерывно ведется журнал транзакций (на диске). И вообще любая операция считается исполненной после ее отражения на диске, не в памяти, поэтому и быстродействие меряется лишь сотнями-тысячами транзакций в секунду. По этому журналу можно восстановить состояние БД в любой предыдущий момент, начиная с создания БД. Важность этого дела приводит к тому, что СУБД при разворачивании отнимает под себя у диска нужную часть с секторами, идущими подряд, а затем внутри этой области ведет свою файловую систему. Ничего более подходящего предложить не могу. Диск - место энергонезависимого хранения данных, а гораздо более быстрая по сравнению с ним память, к сожалению, забывает данные сразу с отключением питания.
Да, по поводу вычисления каждой переменной на каждом тике - аналогом таких операций в СУБД являются триггеры, которые и сами сохраняются в СУБД. Однако я не призываю Вас использовать СУБД, лишь хочу подчеркнуть, что диск - это как раз то самое место, которое годится в случае сбоев.
Спасибо, Влад! Чувствуется ответ компетентного человека. За время обдумывания вопроса в эти дни, да и Ваш ответ подтвердил, что это правильное решение, - придумал следующий вариант: из последовательности переменных составляется текстовая строка через определенный разделитель, далее мы отслеживаем, не изменилась ли эта текстовая строка. Как только замечено отличие хотя бы на 1 знак, сбрасываем строку на жесткий диск вместо старой записи (до полноценной БД, скорее всего, в таких программах нет смысла разрастаться, кроме того, в случае, если с момента сбоя прошло значительное время, даже последние восстановленные данные, скорее всего, уже будут не актуальны, а вот ). В OnInit'e делаем проверку на наличие такой строки на жестком диске. Если есть, то все значения переменных восстанавливаются из нее и советник продолжает работу с последней точки. Тогда мы и данные сохраняем, и не особо нагружаем систему.
Если это подходит, хорошо. Особо нагрузить систему очень сложно, чтобы убедиться, просто замеряйте время исполнения операций, исполняя их, например, по 100 тысяч раз. Но вот складывать все в одну строку для проверки, по-моему, лишнее. И сами преобразования значений в строки, и, особенно, сложение подстрок мне кажутся лишними операциями. Лучше завести структуру, в которой содержатся только элементы, которые надо сравнивать. Один экземпляр со значениями, с которыми надо сравнивать (последними записанными на диск), другой с текущими. Одна функция их сравнит (LastV.a != OperV.a || LastV.b != OperV.b || LastV.c != OperV.c || ...) и вернет необходимость записи на диск. Логические выражения в MQL подсчитываются по короткой схеме, и в случае первого же обнаруженного отличия остальные делаться не будут.
Структура того, что лучше писать на диск - посмотрите файл \config\terminal.ini, ведь он предназначен тоже для возобновления работы после перерыва. А также справку к терминалу "Конфигурация при старте". С разделителями трудно разбираться, лучше дать имя каждому из записываемых значений. Можно будет наглядно просматривать редактором текстов. И считывать проще, особенно с учетом последующего изменения состава хранимых на диске значений. И, в целях отладки, лучше было бы опустошать файл, куда пишете, не каждый раз, а, например, после достижения размера в 10 Мб или 1 Гб. В этих же целях добавил бы в записываемые сведения локальное время. Собственно, время дополнит проверку наличия на диске, ведь прошлогодние сведения вряд ли нужны.

- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Здравствуйте, коллеги-программисты. Заинтересовал меня следующий вопрос, прошу поделиться опытом.
Предположим, имеется программа, которая имеет ряд флагов состояний и требует знания информации о том, какие сделки и в каком статусе находились на предыдущем тике. Одним словом, часть важной информации сохраняется во внутренней памяти программы. Однако если есть требование, чтобы в случае технической неисправности (сбоя терминала, перезагрузки компьютера и т.д.) программу можно было запустить с того места, на котором она остановилась, нужно, чтобы все эти сведения хранились где-то в ином месте. И здесь возникает вопрос, что можно в таких случаях использовать. Конечно, самый простой способ - отправлять эти сведения в csv или ini файлы, однако когда это делаешь на каждом тике, скорость исполнения программы сильно снижается, так как нужно не просто записать сведения, но и открыть/закрыть файл на каждом тике, иначе в случае сбоя несохраненные сведения "улетят".
Мне приходит решение сохранять данные во внутренней памяти и перезаписывать сведения только если происходит изменение состояния (содержания внешнего файла).
Поделитесь опытом, кто как решает подобные проблемы?