Utils.mqh - библиотека утилит.

 
Предлагаю желающим небольшую библиотеку утилит.

Основное в ней - это средства отладки,
т.е. просто вывод диагностики в файл или лог эксперта.

С ее помощью я у себя в скриптах много удивительного обнаружил :))
Многое работает не так, как я ожидал при написании экспертов ...

Только не спрашивайте что там и зачем.
Разжевывать все детали времени нет, приведу только некоторые примеры.
//+------------------------------------------------------------------+
//|                                                         Util.mq4 |
//|                                   Copyright © 2005, Yuri Makarov |
//|                                       http://mak.tradersmind.com |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, Yuri Makarov"
#property link      "http://mak.tradersmind.com"

#include "WinUser32.mqh"
#include <stdlib.mqh>

// Обработчик Тиков.
//  Генерирует события newBar и newTick.
int _prevTime = 0;  // Время предыдущего тика
int start()
{
   int curTime = Time[0];
   if (_prevTime != curTime)
   {
      newBar();
      _prevTime = curTime;
   }
   newTick();
}

// Устранение подвисания терминала при расчете индикаторов.
//  Функция Idle вставляется в цикл расчета индикатора.
int _hwnd = 0;
int Idle()
{
   if (_hwnd == 0) _hwnd = WindowHandle(Symbol(),Period());
   if (_hwnd != 0) SendMessageA(_hwnd,0,0,0);
}

// Iff - функция условного выбора
double Iff(bool check, double TrueValue, double FalseValue)
{
   if (check) return(TrueValue);
   else       return(FalseValue);
}

//-----------------------------------------------------------
// Функции отладки.
//-----------------------------------------------------------
string _LogFile   = "";  // Имя лог файла.
int    _LogHandle = -1;  // Хандлер лог файла.
int    _LogLevel  = 0;   // Уровень отладки.

// Возвращает уровень отладки
int LogLevel() { return (_LogLevel); }

// Открытие лог файла и установка уровня отладки.
int LogOpen(string Name = "", int Level = 1)
{
   LogClose();
   _LogFile  = Name;
   _LogLevel = Iff(Level < 0,0,Level);
   if (Name != "") 
   {
      _LogHandle = FileOpen(Name,FILE_WRITE);
      if (Check(_LogHandle <= 0, "Ошибка открытия Лог файла"))
         MessageBox("" + GetLastError() + ": " + ErrorDescription(GetLastError()),
            "Ошибка открытия Лог файла", MB_OK|MB_ICONWARNING);
   } 
   else _LogHandle = -1;
}

// Закрытие лог файла.
int LogClose()
{
   if (_LogHandle > 0) 
   {
      LogFlush();
      FileClose(_LogHandle);
   }
   _LogLevel = 0;
}

// Сбросить буфер лог файла.
int LogFlush()
{
   if (_LogHandle > 0) FileFlush(_LogHandle);
}

// Вывод сообщения в лог.
//  Level = 0 - выводится всегда, при любом уровне отладки.
int Log(int Level, string mes = "")
{
   if (LogLevel() >= Level)
   {
      string sLevel = "";
      for (int i = 0; i < Level; i++) sLevel = sLevel + "  ";
      if (_LogHandle > 0) 
         FileWrite(_LogHandle, Symbol()+" ("+Period()+") " + sLevel + mes);
      else Print(sLevel + mes);
   }
}

// Проверка условия истинности.
bool Check(bool Cond, string mes)
{
   if (Cond) Log(0, mes);
   return (Cond);
}

//========================================================
//========================================================
//------------------ В рабочей версии закомментировать.
//int newTick(){if (LogLevel() > 0) Check(false,"***");Idle();}
//int newBar(){LogOpen(); LogFlush(); LogClose();}



При использовании библиотеки нужно убрать из скриптов функцию start().
Вместо нее нужно использовать события

int newBar() {}
int newTick() {}


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

Если комуто это не нравится, можно закоментировать в тексте библиотеки функцию start() и использовать ее в скриптах как и раньше.

LogOpen(File = "", Level = 0) - Открытие лога
-- File - имя файла куда пишется лог, если = "", то лог выдается в закладку эксперта в МТ
-- Level - уровень отладки, будут выводиться только строки с уровнем меньше или равным Level.

LogClose() - закрытие лога.
Закрывается файл лога на диске и устанавливается вывод уровня 0 в закладку МТ.

Log(Level, Message) - вывод Message в лог, если Level <= заданному уровню отладки.

Check(Condition, Message) - вывод Message в лог, если выполнено условие Condition.
Возвращает Condition.

Использование.

Пример.

int init()
{
   LogOpen("log.txt",5);
   Log(0,"Init --- "+TimeToStr(LocalTime(),TIME_SECONDS));
   ..............
}

int deinit() 
{ 
   Log(0,"DeInit --- "+TimeToStr(LocalTime(),TIME_SECONDS));
   LogClose(); 
}

int newBar() { Log(1,"NewBar "+TimeToStr(LocalTime(),TIME_SECONDS)); }
int newTick()
{
   Log(2,"NewTick, Ask = "+Ask+" Bid = "+Bid);
   int counted_bars=IndicatorCounted();
   if ( Bars <= 100 ) return(-1);
    ..............

}



Общее правило,
Чем детальнее и обильнее вывод (например в цикле),
тем больше ставится Level в функции Log().

Задавая уровень отладки в LogOpen(),
вы можем управлять глубиной отладки.

Т.е.
LogOpen("", 0) - вывод только самых основных сообщений.
LogOpen("", 1) - более детальный вывод.
LogOpen("", 2) - еще более детальный вывод.
и т.д.

Функция Check() используется для проверки некоторых условий,
например входных параметров на допустимые значения,
инвариантов в циклах (см. Вирта) и пр.

Check выводит в лог всегда, независимо от установленного уровня отладки.

Вот пример лог файла

GBPUSD (1) Init --- 16:25:24
GBPUSD (1)   buf0.size = 0  buf1.size = 0
GBPUSD (1)   NewBar 16:25:24
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2000 counted_bars: 0 Limit: 1988
GBPUSD (1)       AvgRange: 0.00039000
GBPUSD (1)       AvgRange: 0.00039000
GBPUSD (1)       AvgRange: 0.00039000
GBPUSD (1)       AvgRange: 0.00039000
  .....................
GBPUSD (1)       AvgRange: 0.00039000
GBPUSD (1)       AvgRange: 0.00039000
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2000 counted_bars: 1998 Limit: -10
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2000 counted_bars: 1998 Limit: -10
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
  ....................
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2000 counted_bars: 1998 Limit: -10
GBPUSD (1)   NewBar 16:25:28
GBPUSD (1)     NewTick, Ask = 1.83930000 Bid = 1.83890000
GBPUSD (1)     Bars: 2001 counted_bars: 1998 Limit: -9
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2001 counted_bars: 1999 Limit: -10
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2006 counted_bars: 0 Limit: 1994
GBPUSD (1)       AvgRange: 0.00036000
GBPUSD (1)       AvgRange: 0.00036000
  ..........................
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2006 counted_bars: 2004 Limit: -10
GBPUSD (1)   NewBar 16:26:01
GBPUSD (1)     NewTick, Ask = 1.83930000 Bid = 1.83890000
GBPUSD (1)     Bars: 2007 counted_bars: 2004 Limit: -9
GBPUSD (1)     NewTick, Ask = 1.83920000 Bid = 1.83880000
GBPUSD (1)     Bars: 2007 counted_bars: 2005 Limit: -10
GBPUSD (1)     NewTick, Ask = 1.83940000 Bid = 1.83900000
GBPUSD (1)     Bars: 2007 counted_bars: 2005 Limit: -10
GBPUSD (1) DeInit --- 16:26:05
 
Полезная штука. Давно стоило кому-то выложить, я вот никак не созрею =)
Поскольку тестировать тут вряд ли кто-нибудь будет, а если будет, то не скоро, то я решил, что сначала вылизать, а потом выложить. А времени нет.

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

зызы: Понравилась идея "уровней", т.е. приритетов сообщений. Надо бы и у себя сделать... А ещё можно сделать ф-цию отправки мыла и ф-цию вывода на экран в текстлейбл.

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

Согласен, я у себя уже поправил.

А символ с периодом в имя файла вынести.

Не согласен, удобно в имя файла добавить Локалтайм.

зызы: Понравилась идея "уровней", т.е. приритетов сообщений. Надо бы и у себя сделать... А ещё можно сделать ф-цию отправки мыла и ф-цию вывода на экран в текстлейбл.

Насчет уровней идея старая, и наверняка не моя :))
 
Не согласен, удобно в имя файла добавить Локалтайм.

Локалтайм само собой =))) я сделал структуру папок, и одна из них - символ, а другая ТФ
 
Локалтайм само собой =))) я сделал структуру папок, и одна из них - символ, а другая ТФ

Да, наверное.
Убрал у себя символ из лога и добавил время.
А символ и таймфрейм перенес в название файла.
Так вроде бы удобнее .. :))
 
Mak, не смотрел ещё - "Сообщество Экспертописателей" ??? Там я свою "информашку" вчера выложил, достаточно громоздко, конечно, да и наверняка с ошибками =) , но тоже вариант..
 
Смотрел.
Но для меня слишком сложно ...
Или свое всегда кажется проще ..? :))

Я кстати думал что отладка будет сильно тормозить,
но вот смотрю сейчас - индикатор на 2000 баров с отладочным выводом на несколько сот кило успевает эти бары в пределах 1 секунды обработать :))

Нормальная скорость!
 
Но для меня слишком сложно ...

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