Интересное и Юмор - страница 5751

Есть тонкость: ИИ написала код неграмотно с точки зрения архитектурного решения. Опытные программисты с сайта MQL5 будут критиковать такой код — и обоснованно. Для ИИ необходимо формулировать подробное техническое задание, как для студента с первого курса.
Расчёт среднего хода выполняется за 30 дней на каждом тике, не надо пересчитывать на каждом тике историю, которая уже не изменится.

Именно так обычно пишут коды  для Windows индусы, без учёта оптимизации — поэтому windows работает  медленно.

---
Техническое задание

Тема: Оптимизация функции OnCalculate индикатора MQL5

1. Цель

Необходимо оптимизировать реализацию функции OnCalculate , исключив избыточный пересчёт исторических данных на каждом тике.

2. Проблема текущей реализации

В существующем варианте на каждом тике выполняется повторный пересчёт истории за 30 дней. Такой подход приводит к:

  • избыточной нагрузке на процессор;

  • неоправданному повторному анализу уже рассчитанных данных;

  • снижению производительности терминала.

Пересчёт полной истории на каждом тике является неэффективным и должен быть устранён.

3. Требуемая логика работы

  1. При запуске индикатора:

    • однократно загрузить 30 дневных свечей из истории;

    • включить в расчёт текущий (нулевой) бар;

    • выполнить полный расчёт только один раз.

  2. В процессе работы (OnCalculate):

    • не выполнять повторный пересчёт 30-дневной истории на каждом тике;

    • на тиках обновлять только текущий формирующийся бар;

    • пересчитывать историю повторно только при смене дневного бара.

  3. Определение смены дневного бара:

    • реализовать корректный механизм определения появления нового дневного бара;

    • использовать надёжный способ определения смены даты бара на таймфрейме D1.

4. Архитектурные требования

  1. Логику загрузки истории вынести в отдельную функцию.

  2. Эта функция должна вызываться:

    • при старте индикатора;

    • из OnCalculate только в случае смены дневного бара.

  3. Исключить лишние вычисления и повторные обращения к историческим данным без необходимости.

5. Ожидаемый результат

  • История за 30 дней загружается и пересчитывается однократно при инициализации.

  • Повторный пересчёт выполняется только при появлении нового дневного бара.

  • На каждом тике обновляется исключительно текущий бар без перерасчёта всей истории.

  • Код должен быть оптимизирован по производительности и структурирован логически корректно.
    ---

переделай это индикатор YZ_AvgDailyRange30.mq5 но назови его aiYZ_Z_AvgDailyRange30_V2.mq5

этот YZ_AvgDailyRange30.mq5 оставь как пример неправильного архитектурного решения.

//+------------------------------------------------------------------+
//|                                   aiYZ_Z_AvgDailyRange30_V2.mq5  |
//|                                  Автор: YuraZ                    |
//|  Оптимизированная версия: полный пересчёт только при смене D1.   |
//|  На каждом тике обновляется только текущий (0-й) бар.            |
//|  Справка: https://www.mql5.com/ru/docs                           |
//|  Примеры: https://www.mql5.com/ru/code/mt5                       |
//+------------------------------------------------------------------+
#property copyright "YuraZ"
#property link      "https://www.mql5.com"
#property version   "2.00"
#property description "Средний дневной ход (High-Low) за N дней. Оптимизация: пересчёт истории только при смене дневного бара."
#property description "На тике обновляется только формирующийся бар — без полного CopyRates."

#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0

input int InpDays = 30;  // Количество дневных свечей (включая текущий день)

//--- Уникальное имя метки на графике
string LabelName;
//--- Фактическое число дней (защита от InpDays < 1)
int ExtDays;

//--- Кэш для оптимизации: не пересчитываем 30 дней на каждом тике
//    Сумма ходов (High-Low) по барам с индексами 1..(N-1); бар 0 обновляется на тике
double   ExtSumBars1ToN = 0.0;
//    Фактическое количество скопированных дневных баров (30 или меньше при неполной истории)
int      ExtCopiedCount = 0;
//    Время открытия текущего дневного бара (0 = формирующийся бар); для определения смены дня
//    iTime(Symbol(), PERIOD_D1, 0) возвращает время начала текущего D1-бара (см. Доступ к таймсериям)
datetime ExtLastD1BarTime = 0;

//+------------------------------------------------------------------+
//| Загрузка дневной истории и расчёт суммы ходов по барам 1..(N-1)  |
//| Вызывается: при первом запуске и только при смене дневного бара. |
//| Возвращает true при успехе, false при ошибке CopyRates.           |
//+------------------------------------------------------------------+
bool LoadDailyHistoryAndCalc()
  {
   MqlRates daily[];

   //--- CopyRates — единственное обращение к истории за 30 дней в этом цикле вызова
   int copied = CopyRates(Symbol(), PERIOD_D1, 0, ExtDays, daily);

   if(copied <= 0)
     {
      if(copied == -1)
         Print("LoadDailyHistoryAndCalc: CopyRates ошибка ", GetLastError());
      return false;
     }

   //--- Сумма ходов только по барам 1..(copied-1); бар 0 не включаем — он обновляется на каждом тике
   double sum1ToN = 0.0;
   for(int i = 1; i < copied && !IsStopped(); i++)
      sum1ToN += (daily[i].high - daily[i].low);

   ExtSumBars1ToN   = sum1ToN;
   ExtCopiedCount   = copied;
   //--- Время открытия текущего D1-бара — по нему определяем смену дня в OnCalculate
   ExtLastD1BarTime = daily[0].time;

   return true;
  }

//+------------------------------------------------------------------+
//| Обновление текста метки на графике                               |
//+------------------------------------------------------------------+
void UpdateLabel(double avg_range, int bars_count)
  {
   int digits = (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS);
   string avg_str = DoubleToString(avg_range, digits);
   string label_text = "Средний дневной ход (" + IntegerToString(bars_count) + " дн.): " + avg_str;
   ObjectSetString(0, LabelName, OBJPROP_TEXT, label_text);
   ChartRedraw(0);
  }

//+------------------------------------------------------------------+
//| Инициализация индикатора                                          |
//+------------------------------------------------------------------+
int OnInit()
  {
   ExtDays = (InpDays < 1) ? 30 : InpDays;
   if(InpDays < 1)
      Print("InpDays должно быть >= 1. Используется ", ExtDays, " дней.");

   LabelName = "aiYZ_ADR30_V2_" + IntegerToString(ChartID());

   if(!ObjectCreate(0, LabelName, OBJ_LABEL, 0, 0, 0))
     {
      Print("Ошибка создания метки: ", GetLastError());
      return(INIT_FAILED);
     }

   ObjectSetInteger(0, LabelName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, LabelName, OBJPROP_XDISTANCE, 10);
   ObjectSetInteger(0, LabelName, OBJPROP_YDISTANCE, 20);
   ObjectSetInteger(0, LabelName, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
   ObjectSetString(0, LabelName, OBJPROP_FONT, "Arial");
   ObjectSetInteger(0, LabelName, OBJPROP_FONTSIZE, 12);
   ObjectSetInteger(0, LabelName, OBJPROP_COLOR, clrWhite);
   ObjectSetString(0, LabelName, OBJPROP_TEXT, "ADR30 V2: ...");
   ObjectSetInteger(0, LabelName, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, LabelName, OBJPROP_BACK, false);

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Деинициализация                                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectDelete(0, LabelName);
  }

//+------------------------------------------------------------------+
//| OnCalculate: оптимизированная логика                              |
//| — Полный пересчёт истории только при первом запуске и смене D1.  |
//| — На каждом тике обновляется только ход текущего (0-го) бара.     |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   //--- 1) Первый запуск или кэш ещё не заполнен — однократная полная загрузка истории
   if(prev_calculated == 0 || ExtLastD1BarTime == 0)
     {
      if(!LoadDailyHistoryAndCalc())
         return(rates_total);
     }

   //--- 2) Определение смены дневного бара
   //    iTime(symbol, timeframe, shift) — время открытия бара (см. Доступ к таймсериям и индикаторам)
   //    shift=0 — текущий (формирующийся) бар на D1; при смене дня это время меняется
   datetime current_d1_bar_time = iTime(Symbol(), PERIOD_D1, 0);

   if(current_d1_bar_time != ExtLastD1BarTime)
     {
      //--- Новый дневной бар: повторная загрузка истории и пересчёт суммы по барам 1..(N-1)
      if(!LoadDailyHistoryAndCalc())
         return(rates_total);
     }

   //--- 3) Текущий бар (0): ход обновляется на каждом тике без CopyRates за 30 дней
   //    iHigh / iLow(symbol, timeframe, shift) — High/Low бара (shift=0 — текущий бар)
   double range_bar0 = iHigh(Symbol(), PERIOD_D1, 0) - iLow(Symbol(), PERIOD_D1, 0);

   //--- Среднее = (сумма по барам 1..N-1 + ход текущего бара) / N
   double avg_range = (ExtCopiedCount > 0)
                      ? (ExtSumBars1ToN + range_bar0) / (double)ExtCopiedCount
                      : 0.0;

   UpdateLabel(avg_range, ExtCopiedCount);

   return(rates_total);
  }
//+------------------------------------------------------------------+
Vitaly Murlenko #:

Спасибо, Юра. Очень показательный пример. Есть даже фишки, которые следует взять на заметку для общения с ИИ.

На MQl4 наберу руками код вывода на экран среднестатистического расстояния 30 последних дневных свеч минут, скажем, за 10-15. Ну может ещё покопаюсь минут 5-10 с позиционированием лейбы на экране. Отладка может занять неопределённое (пусть не большое) время. В целом, при старте с нуля и "под ключ", ну, скажем, час уйдёт. Но ни как не три минуты! Экономия времени на лицо.

Подобное Вашему задание (промпт) я могу отдать тому же deepseek или qwen. Они работают с сайта и для подобных нужд бесплатны. Эти 2 ИИ сделают тоже всё минуты за 2-3. И при этом у меня нет геморроя с иностранным языком, с покупкой памяти, и прочими сопутствующими делами!

Это честная оценка.

Виталий, всё так!
Уже есть много бесплатных и вполне рабочих вариантов, правда, честно, не знаю, как DeepSeek кормить данными - учебниками и примерами, в Cursor это легко.
Что касается времени — думаю, да: если с нуля писать даже такой код, это точно не 3 минуты. А еще и с комментариями.
Промты я часто пишу в виде тезисов — потом даю промт «на съедение» в ChatGPT (у меня он тоже платный — платный всё же чуть более качественно работает), а затем кидаю в Cursor. Можно и в курсор но там токены жалко, более дорогие.
Чуть выше я кинул пример задания, где попросил ИИ оптимизацию, как пишут хорошие программисты с MQL5.
Вот уверен: ты бы с первого раза написала правильно, а не «индусский» вариант с итерацией на каждом тике.

К чему это я: за ИИ ещё надо выносить горшки и утирать сопли, подносить ей чай и кофе.
Синьоров эта штука ещё не потеснила. Джунов — да, практически уже уничтожила. 

Конечно все можно в deepseek, только чуть больше усилий.




Упс. Возникло желание сделать эксперимент и снять видео о том, как это всё работает. В том смысле, что запустить секундомер и посмотреть, за сколько времени 2 вышеупомянутых ИИ справятся с поставленной задачей. Я попробую это сделать, но чуть позже - нужно дела разгрести. Обновил в мобиле Госуслуги и теперь не могу авторизоваться от слова совсем. Нужно топать с паспортом в "Мои документы". Печальный сервис Госуслуги :(
Yuriy Zaytsev #:

Задачу нужно тщательно формулировать.

А это как ? 


Volodymyr Zubov #:

А это как ? 


Конечно, не "покончил жизнь", а "совершил попытку самоубийства".
Конечно ИИ интересен. Особенно тем, кто не программист ))) и кто ненаидит английский ))) Но мантры про правильные промты, после которых получишь 100% что хотел - полный бред на сегодняшний день. В 99% случаев будут косяки. ИИ забывает промт почти сразу. Хотя я нашёл выход в 4 ИИ ))))))) которые какие то моменты "лучше" делают.

Volodymyr Zubov #:

А это как ? 


Привет Владимир!
Да , ответы сформулированные ИИ часто удивляют, не понятно как этот ответ был рожден - галлюцинацией ИИ или

из инета из разных источников по разному.

Михаил Шерстнёв #:
Конечно ИИ интересен. Особенно тем, кто не программист ))) и кто ненаидит английский ))) Но мантры про правильные промты, после которых получишь 100% что хотел - полный бред на сегодняшний день. В 99% случаев будут косяки. ИИ забывает промт почти сразу. Хотя я нашёл выход в 4 ИИ ))))))) которые какие то моменты "лучше" делают.

Я бы, пожалуй, относился к этим штукам как к инструменту, а не как к мантре или волшебной таблетке.
Примерно как с любым инструментом: можно взять шило, чтобы аккуратно починить ботинок, а можно тем же шилом случайно проколоть палец.
Сам инструмент вполне годный - зависит от того, как пользоваться.
А использование нескольких ИИ параллельно как раз нормальная практика:
сравнить ответы, выбрать лучшее, собрать итоговое решение.
Это уже не «вера в мантру», а вполне логичный подход к инструменту.
Yuriy Zaytsev #:
Я бы, пожалуй, относился к этим штукам как к инструменту, а не как к мантре или волшебной таблетке.
Примерно как с любым инструментом: можно взять шило, чтобы аккуратно починить ботинок, а можно тем же шилом случайно проколоть палец.
Сам инструмент вполне годный - зависит от того, как пользоваться.
А использование нескольких ИИ параллельно как раз нормальная практика:
сравнить ответы, выбрать лучшее, собрать итоговое решение.
Это уже не «вера в мантру», а вполне логичный подход к инструменту.
У меня основная борьба происходит с творческим подходом ИИ. Его желание сломать рабочий код почти неистребимо )))) 
Читал статью, где утверждалось, что сейчас ИИ рулит другими ИИ и обращаясь с написанием кода зачастую попадаешь на ИИ заточенный на написание стихов, но если случайно попал по адресу - тушите свечи. И склонен верить. Несколько раз попадал по адресу ))))
Друг утверждает что вообще "взламывал" ИИ, но при обнолении версии это пропало (типа соершенно другое взаимодействвие)