Автоматическая инициализация и переинициализация эксперта из файла

 
Задача: восстановить окружение эксперта (данные о позиции, счётчики и т.д.) после переинициализации, перезагрузки в случае сбоя системы и т.п.

Решение: каждое изменение в динамических переменных эксперта сохраняем в файл. Во время OnInit(), всё это дело из файла обратно грузится на место.

Однако, прошлое состояние переменных нельзя загружать из файла если:
  • изменилась структура файла (версия не совпадает, новый билд эксперта). Элементарно проверяется, не проблема.
  • в прошлый раз бот глюкнул. Допустим, хрякнулся по стопауту или завис или перебрал лимит ошибок, тогда в файле могут быть переменные, которые приводят к ошибке сразу. Частично это проверить очень легко (лимит ошибок учесть, запись о критической ошибке...), но это решение не полное.
  • файл просто слишком "пыльный". Допустим, в прошлый раз эксперт загружали X дней назад или даже сегодня, но инфа в нём уже устарела. Как это проверить - фиг знает.

Сейчас сделал так: анализирую причину OnDeinit(), если закрывается программа, тогда удаляю глобаль терминала (типа флаг переинициализации).

Когда во время OnInit() нет этого флага, приходится каждый раз спрашивать пользователя тупым мессадж боксом "восстановить переменные из фала?".

Это безумно тупой и неудобный способ!


Вопрос: как полностью автоматизировать такое решение?

Как определить, когда файл нельзя загружать, а когда можно?

Хотя бы сократить вызов этого мессадж бокса до минимума.

 

MQL4 или MQL5 ?

Если MQL5 , то:

в OnInit() проверяем: 

1. Позицию

if ( PositionSelect(_Symbol) )
{
}
else
{
}

 2. Ордера:

( я, если произошел какой-либо сбой, просто все ордера тупо удаляю, чтобы не разбираться "откуда ноги растут" )

//+------------------------------------------------------------------+
//| Expert Remove orders function                                    |
//+------------------------------------------------------------------+
void RemoveOrders()
{
  int orders_total = OrdersTotal();
//---  
  if ( orders_total > 0 )
  {
    for ( int i = ( orders_total - 1 ); i >= 0; i-- )
    {
      ulong temp_order_ticket = OrderGetTicket( i );
      
      if ( OrderSelect( temp_order_ticket ) )
      {
        string temp_symbol = OrderGetString( ORDER_SYMBOL );
        
        if ( ( temp_symbol == sec_symbol ) || ( temp_symbol == _Symbol ) )
        {
          RemoveOldOrder( temp_order_ticket );
        }
      }
    }
  }
}

 3. Глобальные переменные терминала:

  if ( !GlobalVariableCheck( "trans_count" ) )
  {
    datetime a_time = GlobalVariableSet( "trans_count", 0 );
    
    if ( ulong( a_time ) == 0 )
    {
      MessageBox( "Глобальная переменная терминала 'Счётчик транзакций' не создана!", "Ошибка", MB_OK | MB_ICONHAND );
      return( INIT_FAILED );
    }
  }

 4. Переменные, которые необходимо сохранять

a) Загрузка:

//+------------------------------------------------------------------+
//| Expert Load setings function                                     |
//+------------------------------------------------------------------+
void LoadSettings()
{
  string file_name = _Symbol + ".dat";
  int file_handle;
//---  
  if ( FileIsExist( file_name, 0 ) )
  {
    file_handle = FileOpen( file_name, FILE_READ|FILE_BIN );
    
    if ( file_handle != INVALID_HANDLE )
    {
      e_high = FileReadLong( file_handle );
      a_profit = FileReadLong( file_handle );
      e_low = FileReadLong( file_handle );
      ord_delta_high = FileReadLong( file_handle );
      ord_delta_low = FileReadLong( file_handle );
      order_delta = FileReadLong( file_handle );
      exit_delta = FileReadLong( file_handle );
      FileClose( file_handle );
    }
  } 
}

 б) Сохранение ( OnDeInit() )

//+------------------------------------------------------------------+
//| Expert Save settings function                                    |
//+------------------------------------------------------------------+
void SaveSettings()
{
  string file_name = _Symbol + ".dat";
  int file_handle;
  bool file_found = true;
//---  
  if ( FileIsExist( file_name, 0 ) )
  {
    if ( FileDelete( file_name, 0 ) ) file_found = false;
  }
  else
  {
    file_found = false;
  }
//---
  if ( !file_found )
  {
    file_handle = FileOpen( file_name, FILE_WRITE|FILE_BIN );
    
    if ( file_handle != INVALID_HANDLE )
    {
      FileWriteLong( file_handle, e_high );
      FileWriteLong( file_handle, a_profit );
      FileWriteLong( file_handle, e_low );
      FileWriteLong( file_handle, ord_delta_high );
      FileWriteLong( file_handle, ord_delta_low );
      FileWriteLong( file_handle, order_delta );
      FileWriteLong( file_handle, exit_delta );
      FileClose( file_handle );
    }
  } 
}
 
Fry_Антон:
Задача: восстановить окружение эксперта (данные о позиции, счётчики и т.д.) после переинициализации, перезагрузки в случае сбоя системы и т.п.

Встречный вопрос - Зачем?

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

 
Fry_Антон:
 Задача: восстановить окружение эксперта (данные о позиции, счётчики и т.д.) после переинициализации, перезагрузки в случае сбоя системы и т.п.
Пересчитываю
 
Vasiliy Sokolov:

Встречный вопрос - Зачем?

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

Особенности фьючерсного рынка.

Не всё можно пересчитать. То что можно, разумеется обновляю из окружения, но... Ну вот в качестве примера:

На клирингах позиция и ордера закрываются/открываются. Терминал фиксирует сделку и удаляет ордера на день (а ордера до отмены запрещены брокером). Приходится создавать новые ордера.

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

Так что учёт таких параметров приходится вести свой собственный.

Есть ещё счётчики кол-ва заявок за секунды/минуту/час/день, счётчики не фатальных ошибочных действий и т.д. и т.п.

Я бы с радостью отказался от файла! Если бы это было реально. =(

Бывает ведь и такая ситуация: терминал рухнул (сегодня билды стабильные, а раньше постоянно было такое и не факт, что всегда будут только стабильные релизы).

После краха терминала: быстрая перезагрузка и автозагрузка - восстановление из файла и всё работает.

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


Так что для меня вопрос очень актуальный: как не загружать переменные из файла, который устарел либо опасен для загрузки?

 
Михаил:

MQL4 или MQL5 ?

Если MQL5 , то:

в OnInit() проверяем: 

1. Позицию

 2. Ордера:

( я, если произошел какой-либо сбой, просто все ордера тупо удаляю, чтобы не разбираться "откуда ноги растут" )

 3. Глобальные переменные терминала:

 4. Переменные, которые необходимо сохранять

a) Загрузка:

 б) Сохранение ( OnDeInit() )

Сделал почти так. Только файл сохраняю на OnTrade() с таймером.

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

Я создал базовую структуру в которую помещается всё что надо для файла (кроме несколько строковых значений).

Имя структуре объявил из одной буквы, так что код вполне короткий выходит (b.volume почти как volume). Ну и сохранять удобно через оператор = всю структуру сразу.

 
Fry_Антон:

...

Вопрос: как полностью автоматизировать такое решение?

...

Принципиально другим подходом в программировании советников.

 
Dmitry Fedoseev:

Принципиально другим подходом в программировании советников.

Разверните ответ до разумной полезной мысли и я буду Вам благодарен.

В чём заключаются базовые принципы, на основании которых код эксперта получается "лучше"?

 
Fry_Антон:

Разверните ответ до разумной полезной мысли и я буду Вам благодарен.

В чём заключаются базовые принципы, на основании которых код эксперта получается "лучше"?

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

Клиринг это действительно самая замороченная проблема.  Но это не проблема длительного хранения данных (или их устаревания), можно и в простых переменных в эксперте хранить данные (немного рискованно, но всего лишь 5 мин). Здесь сложность в том, как разобраться потом. Можно для каждого ордера создавать группу глобальных переменных терминала, можно и цену открытие в них хранить. Затем, когда появятся непромаркированные ордера (или на открытии нового дня)  смотрим в истории последние закрытые, сопоставляем по тем признакам по которым можно (например лот), и перебрасываем новому ордеру все глобальные переменные от закрытого ордера. 

 

Антон!

Вы слишком сильно "заморачиваетесь" по этой проблеме.

Понятно, что Вы хотите грамотно восстановить работу эксперта после аварийной

ситуации. Я, поначалу, то же голову ломал.

Но потом решил, что такие ситуации крайне редки

(из собственного опыта полуторогодовой торговли на реале МТ5), поэтому я решил, что не стоит

"заморачиваться" с выставленными ордерами, а просто "прибить" всё, что существует после падения.

Ордера до падения были выставлены, если они исполнились, то ничего нельзя сделать, а если

до сих пор "болтаются", то убив их, и выставив заново в соответствии с торговой ситуацией, Вы НИЧЕГО не потеряете!

Тогда останется только позиция - она есть или нет.

Что касается записи/чтения переменных из файла.

У меня в советниках есть "горячее" (во время работы) изменение переменных, поэтому я их

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

Проблему ВЫ сами себе создаёте!

Подумайте об этом! 

P/S MT5 - это не MT4, где ордера очень важны!

В МТ5 нужно отталкиваться от ПОЗИЦИИ, а не от ордеров. 

 
Fry_Антон:

Разверните ответ до разумной полезной мысли и я буду Вам благодарен.

В чём заключаются базовые принципы, на основании которых код эксперта получается "лучше"?

Ответил в личке.

З.Ы. Ваши примеры не валидны. Нет таких проблем на Фортс. Конечно, можно любую проблему выдумать, а потом попытаться долго ее решать. Но зачем ее решать, когда проще не выдумывать?

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