Особенности языка mql5, тонкости и приёмы работы - страница 339

Ошибка транскодирования в заголовке платформы \MQL5\Include\Math\Stat\Math.mqh после преобразования файла из кодировки UTF-16 в UTF-8.

Строка 5299:

//| Ссылка:                                                       |
//| Хайндман, Р. Дж. и Фан, Ю. (1996)                                |
//| «Выборка квантилей в статистических пакетах»,                      |
//| «American Statistician», т. 50, с.361– 365.                      |

amrali #:

Ошибка транскодирования в заголовке платформы \MQL5\Include\Math\Stat\Math.mqh после преобразования файла из UTF-16 в UTF-8.

Строка 5299:


Похоже, проблема на вашей стороне?

Я также проверил с помощью B6090.

Alain Verleyen #:

Похоже, проблема у вас?

Я также проверил с помощью B6090.

Спасибо за подтверждение.
b6157, при увеличении массива ArrayResize принудительно обнуляет доп. элементы.
double GetTrash( const uint Size = 1e8 )
{  
  double Res = 0;  
  double Array[];
  
  for (int i = ArrayResize(Array, Size); i-- > 0;)
    Res += Array[i];
    
  return(Size ? Res / Size : 1);  
}

void OnStart()
{
  Print(GetTrash()); // 0
}
Статические массивы (и переменные) не инициализируются.
fxsaber #:
b6157, при увеличении массива ArrayResize принудительно обнуляет доп. элементы. 
Ну хз, без подтверждения разрабов, я бы на это не полагался. А в справке это нигде не упоминается.

Шаблон для контроля скользящего максимального просадки в режиме реального времени на языке MQL5:

Советники проп-фирм требуют механизма контроля скользящего максимального просадки, который отслеживает максимальный пик собственного капитала и закрывает все позиции, если текущий собственный капитал опускается ниже порогового значения от этого пика. Тонкость, которую упускают большинство разработчиков MQL5: AccountInfoDouble(ACCOUNT_EQUITY) включает в себя плавающий нереализованный P&L, что правильно для данной цели — однако пиковое значение собственного капитала должно обновляться только в функции OnTick(), а не в OnTradeTransaction(), чтобы избежать «фантомных» пиков из-за частично исполненных ордеров:

double g_peakEquity = 0;
double g_maxDrawdownPct = 0.08; // 8 % просев

void OnTick()
{
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double balance = AccountInfoDouble(ACCOUNT_BALANCE);

   // Обновлять пиковое значение только на основе подтвержденного капитала, а не данных на момент совершения сделки
   if(equity > g_peakEquity)
      g_peakEquity = equity;

   // Проверить превышение максимального просадки
   if(g_peakEquity > 0)
   {
      double drawdown = (g_peakEquity - equity) / g_peakEquity;
      if(drawdown >= g_maxDrawdownPct)
      {
         CloseAllPositions(); // атомарное сглаживание
         ExpertRemove();
      }
   }
}

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

fxsaber #:
b6157, при увеличении массива ArrayResize принудительно обнуляет доп. элементы.

Обнуление не гарантируется.

Slava #:

В Тестере в tst-файл пишутся данные графика Balance/Equity.

//+------------------------------------------------------------------+
//| Структура для графика тестирования                               |
//+------------------------------------------------------------------+
struct TesterTradeState
{
  __int64           time;                // текущее тестовое время
  double            balance;             // текущий баланс
  double            equity;              // текущий equity
  double            value;               // текущее рассчитанное значение нагрузки на депозит


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


Табличные данные этого графика.

                  [time] [balance] [equity] [value]
[ 0] 2026.10.16 00:00:00  10000.00 10000.00    0.00
[ 1] 2026.10.16 04:34:40  10000.00  9752.10    0.00
[ 2] 2026.10.16 17:27:40  10000.00 10270.10    4.06
[ 3] 2026.10.19 12:12:00  10000.00  9999.00    4.17
[ 4] 2026.10.19 14:16:40  10000.00 10051.60    4.15
[ 5] 2026.10.20 13:09:40  10000.00  9396.80    4.44
[ 6] 2026.10.20 23:19:00  10000.00  9508.00    4.39
[ 7] 2026.10.22 01:00:40  10000.00  9737.30    4.28
[ 8] 2026.10.22 08:48:20  10000.00  8947.20    4.66
[ 9] 2026.10.22 11:26:00  10000.00  9189.80    4.54
[10] 2026.10.22 11:27:20  10000.00  9221.00    4.52
[11] 2026.10.23 17:30:20  10000.00  8035.00    5.19
[12] 2026.10.23 22:33:40  10000.00  8257.60    5.05
[13] 2026.10.26 03:03:20  10000.00  8060.90    5.18
[14] 2026.10.26 19:13:40  10000.00  8578.60    4.86
[15] 2026.10.27 09:46:20  10000.00  8330.40    5.01
[16] 2026.10.27 10:53:20  10000.00  8170.90    5.11
[17] 2026.10.28 02:10:40  10000.00  8987.70    4.64
[18] 2026.10.28 20:54:20  10000.00  8714.60    4.79
[19] 2026.10.28 22:01:40  10000.00  9105.90    4.58
[20] 2026.10.29 20:32:40  10000.00  8332.30    5.01
[21] 2026.10.29 23:00:30   8492.10  8492.10    0.00


Не понимаю алгоритма, как принимается решение, что нужно сделать очередную запись. Цветом выделил две записи, между которыми 80 секунд. Смотрел график котировок за эти 80 секунд - там штиль. В общем, просьба пояснить. Но больше предложение.


Когда составляют портфель из двух ТС, то стараются посчитать корреляцию результатов этих ТС.

  1. Для этого берут два Equity-вектора - значения Equity каждого бэктеста в одинаковых time-точках (например, в начале каждого часа или в начале каждых суток).
  2. И после преобразования вычисляют корреляцию между ними.
    vector GetVector( const double &Array[] )
    {
      vector Vector;
      
      Vector.Assign(Array);
      
      return(Vector);
    }
    
    double GetCorr( const double &Array1[], const double &Array2[] )
    {
      return(GetVector(Array1).CorrCoef(GetVector(Array2)));
    }
    
    void ChangeEquity( double &Equity[] )
    {
      for (int i = ArraySize(Equity) - 1; i > 0; i--)
        Equity[i] = Equity[i] / Equity[i - 1] - 1;
          
      Equity[0] = 0; // ArrayRemove(Equity, 0, 1);
    }
    
    void OnStart()
    {
      double Equity1[]; // Equity первой ТС - запись каждый час.
      double Equity2[]; // Equity второй ТС - запись каждый час.
    
      ChangeEquity(Equity1);
      ChangeEquity(Equity2);
      
      Print(GetCorr(Equity1, Equity2)); // Корреляция двух ТС.
    }

Так вот просьба подумать над возможностью всегда записывать в tst каждый час Equity/Balance-значение в одиночном проходе.

Тогда будут данные для вычисления корреляций между ТС. Получим и график Equity/Balance, где абсцисса - время. Спасибо.

Строка для поиска: Uluchshenie 165.