English 中文 Español Deutsch 日本語 Português
preview
Возможности СhatGPT от OpenAI в контексте разработки на языках MQL4 и MQL5

Возможности СhatGPT от OpenAI в контексте разработки на языках MQL4 и MQL5

MetaTrader 5Трейдинг | 27 июня 2023, 09:59
3 166 27
Evgeniy Ilin
Evgeniy Ilin

Разделы



Введение

Начну с краткого экскурса для тех, кто не знает, что такое ChatGPT и с чем его едят. Данная технология является одной из вариаций искусственного интеллекта от компании OpenAI, предназначенного для помощи человеку в решении совершенно различных задач. Выглядит этот инструмент как обычный текстовый чат в мессенджере, только на том конце находится так называемый искусственный интеллект, который отвечает вам в текстовом виде.

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

Нам же данная модель будет интересна лишь с одной стороны — разработка прибыльных торговых систем. Мне стало очень интересно, как оптимально и правильно использовать подобную технологию для более быстрой и легкой разработки торговых систем. В конечном итоге, тот, кто первый начнет правильно применять ее по назначению, тот уменьшает как себестоимость любой разработки, так и трудозатраты, что дает очевидные конкурентные преимущества (кто знает, тот поймет о чем я).


Перспективы применения ChatGPT в рамках MQL5

Я думаю, в данном разделе стоит подробнее остановиться на том, какие перспективы использования в себе таит данная технология. После довольно подробного исследования на собственных примерах я понял, что подобная технология лишь начало чего-то грандиозного. Но даже сейчас я могу выделить следующие ее возможности:

  • Генерация любых MQL4 и MQL5 кодов
  • Рефакторинг и оптимизация рабочего кода
  • Очистка кода
  • Добавление комментариев в код
  • Исправление ошибок в коде
  • Реализация математических моделей
  • Последующее построение кода по математическим моделям
  • Модернизация любых известных алгоритмов и математических моделей
  • Ускорение процесса разработки советников
  • Кладезь информации

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

  1. "Сейчас мы с тобой сделаем супер алгоритм"
  2. Нейтралы, осторожно относящиеся к ИИ, сомневающиеся в пользе
  3. Нельзя быль лучше человека, все это очередной хайп

От себя я могу сказать, что я начал знакомство с данной технологией достаточно давно и в начале относился к третьей категории. В первые два дня общения с этим ИИ, я резко перешел из третьей в первую категорию, после чего начался более интересный и довольно неприятный процесс корректировки собственных убеждений, что больше похоже на откат к категории "1.5", которая является уже реальной оценкой данной технологии.
Нужно сказать, что данная технология полезна, но не настолько, как вы подумаете изначально. В данной связи стоит отдать должное разработчикам и маркетологам данной технологии, хотя бы за то, что она создает невероятный "вау" эффект от использования в первые пару-тройку дней, что достаточно для цепной реакции саморекламы. За это им большой палец вверх.

Чтобы понять это, необходима очень большая практика в общении с данным ИИ. Лично у меня было около ста различных диалогов с ним на различные темы. Можно сказать, что я обрел достаточно практики в использовании данной технологии, чтобы начать применять ее для MQL5. Но прежде чем перейти к практическому применению, мне просто необходимо вам сообщить некую очень важную информацию, а для этого нам нужно будет заглянуть поглубже под капот данной технологии.


Подвохи и неприятные моменты связанные с ChatGPT

Так называемый «Вау-эффект», который накроет вас в первые дни использования данной технологии, связан с тем, что это в первую очередь текстовая модель, которая предназначена для преобразования вашего вопроса в ответ. Причина, по которой ее ответы вам нравятся, кроется в том, что создатели научили данную модель очень красиво лгать. Да, это не шутка! Она настолько красиво лжет, что вы сами захотите поверить в это, и даже после многих попыток ее разоблачения, данная модель будет часто выдавать следующее:

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

Короче говоря, он всячески будет отлынивать от того, что вы ему сказали сделать, пользуясь при этом несовершенством вашего "промпта". При ошибках будет пытаться оправдаться таким образом, чтобы в дальнейшем вы не смогли его поймать на том же, а если понимает, что вы его раскололи, пытается смягчить вашу негативную реакцию определенными отписками и психологическими приемами. В целом, я думаю, что алгоритм заточен под оптимальное ресурсопотребление при допустимом уровне удовлетворенности пользователей. То есть цель в данном случае — не дать вам наиболее качественное решение задачи, а выдать вам такое решение, которое вы таковым посчитаете, в силу совершенно разных возможных причин. Получается, цель — положительная реакция пользователя, и не так важно, правильно ли решена задача. Вот к этому он стремится. Да, с точки зрения маркетинга это правильно, и в данной связи этот ИИ просто красноречивый дьявол.

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

Для того, чтобы начать понимать, как задавать такие вопросы, нужно понять следующее:

  1. Структура и вид "промпта" не важны, важны детали и качество вопроса. (Он все понимает и незачем читать какие-то гайды из интернета, как составлять промпты. Пишите как есть, но без сленга.)
  2. Сложные вопросы или просьбы делите на подпункты. (Упрощайте и дробите вопросы и получите более точные, простые и ясные ответы.)
  3. Чем умнее и пунктуальнее вы, а значит и ваш вопрос — тем полезнее ответ.
  4. Он не даст вам супер идею или алгоритм. (Он не обладает широтой мышления, планирования и интеллектуальным творчеством. Но будет по началу казаться, что он это может, просто потому что, как я сказал уже, он отлично лжет.)
  5. Рассуждать о применении данной технологии следует исключительно в контексте ускорения вашей работы и снижения ваших трудозатрат.
  6. Каждая новая просьба должна быть наименее зависима от всего диалога. (Он не может тащить за собой весь диалог и старые сообщения не всегда учитывает при ответе. Попробуйте и вы поймете, о чем я.)
  7. Чем более комплексный и сложный вопрос с множеством деталей, тем больше вероятность получить полную ахинею. (Это, как объяснение второго подпункта.)
  8. У него нет доступа в интернет, и все ответы он генерирует только исходя из своей базы знаний. (Если вы его сильно замучаете, чтобы он залез в интернет и что-то сделал, он скажет, что сделал и выдаст вам старые данные из своей базы или подгонит ответ, исходя из вашего контекста вопроса, выдав их за новые. Учтите это. А сделает он это просто потому, что он видит, что спорить с вами бесполезно и лучше убедить вас в том, что он все сделал, и вы тогда отстанете.)
  9. ChatGPT 3.5 обучен до 2019 года. (А это значит, что у него нет никакой информации о будущем после 2019 года, до очередного сеанса обучения, санкционированного разработчиками.)
  10. ChatGPT 4.0 обучен до 2021 года. (Он лучше потому, что очень мало лжет и старается всегда корректно отвечать. Когда попробуете позадавать вопросы и сравнить, увидите, как 3.5 лжет и не краснеет.)

На самом деле еще очень много мелких неприятных моментов, которые портят впечатление о данной технологии. Но тем не менее, если бы эта технология не была полезной, я бы не писал о ней. Если посмотреть на эти проблемы с точки зрения того, что вы думали, что вы общаетесь со "Skynet", то все вышеперечисленное является фактом того, что никакой это не искусственный интеллект. Но если быть более прагматичным и подумать, а все ли так плохо и какие рутинные операции я смогу выполнять быстрее и качественнее с помощью данной технологии, то я уверен, вы не будете столь категоричными. Нужно лишь подумать, как использовать все это в разработке торговых систем.

Завершая этот раздел, хочу акцентировать ваше внимание на самом важном и основном пункте, который вам нужно запомнить и всегда помнить:

  • Всегда перепроверяйте ответы ChatGPT и особенно числа, формулы и сгенерированный код

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


Возможности использования ChatGPT для решения математических задач и разработки математических моделей для использования в коде

Так как данная модель текстовая, то несложно догадаться, что если писать формулы в правильном формате, то она их будет понимать и более того, может совершать математические преобразования и решать задачи. При разработке многих торговых систем вам потребуется помощь в создании математических формул и выражений. Возможно решение некоторых возможных математических задач с последующим воплощением их в код. Существует следующий формат записи математических формул, который ChatGPT понимает и в котором также выдает ответ:

  • LaTeX

Пример использования латекс формата для написания формул:

Код:

E &=& mc^2\\
m &=& \frac{m_0}{\sqrt{1-\frac{v^2}{c^2}}}

Вставляем это в любой бесплатный латекс преобразователь и получаем визуализацию данных всем знакомых выражений:

Формулы энергии и релятивистского расширения массы от Эйнштейна

Думаю, теперь вам будет понятно, как визуально интерпретировать его ответы в формате LaTeX. Главное, не забывайте его просить сгенерировать формулы именно в этом формате, если ответ содержит математические выражения. Существуют также нейросети, способные к обратному преобразованию формул на картинках или в других форматах в нужный нам формат. Думаю, при желании вы найдете эти инструменты, если они вам нужны. Моя же задача — показать вам наличие такой возможности.

Есть Telegram-боты, объединяющие множество нейросетей, в том числе ChatGPT, и функцию обратного преобразования картинки в формат LaTeX. При желании вы сможете найти одного из них в моем профиле. Этот бот сделан моим знакомым и проверен мной лично. Пользуйтесь на здоровье.

Можно попросить ChatGPT, например, решить неравенство или уравнение, как в численном, так и в явном виде. Можно также попросить решить системы уравнений или неравенств, а также дифференциальные уравнения или интегралы, или совершить любые требуемые математические преобразования. Единственное, я могу сказать, как математик — не всегда он делает это качественно и рационально и не всегда делает до конца. Это, собственно, должно дополнительно вас мотивировать для перепроверки результатов его "колдовства".

Конечно, это будет полезно тем, кто совсем не знает математики, с некоей вероятностью и доступным качеством данной технологии. Я бы сказал, что при длительном использовании вы будете допускать больше ошибок, и ваше решение будет достаточно нерациональным и корявым. Тем не менее, вы закроете частично ваши проблемы с математикой для вашего кода, учитывая, что в коде обычно используются лишь численные методы и не такая уж и сложная математика. Дифференциальной математики здесь совсем нет.


Правильный подход к генерации кодов на языках MQL4 и MQL5

Здесь начинается самое интересное. Учитывая, что размеры кодов всех достаточно качественных и более-менее приличных торговых систем достаточно большие, стоит подумать о том, как подойти к процессу генерации подобных кодов. Здесь основным препятствием является то, что размер ответа на ваш вопрос ограничен определенным количеством знаков, и после многочисленных попыток генерировать большие и сложные коды я пришел к тому, что каждый его вывод кода должен быть достаточно коротким. А это значит, что код должен быть выведен по частям. А как добиться этого? Ответ очень прост — нужно составить план разработки советника, индикатора или скрипта.

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

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

Дополнительным и важным плюсом является то, что можно попросить его самому подготовить план советника или иного кода, с указанием ваших требований, а потом просто реализовывать его же план по кускам. Хорошо, когда есть примерное или точное представление о том, каков будет алгоритм вашего советника и какие индикаторы или иные подходы он будет использовать. Но если данного представления нет, можно сначала поговорить с ним и попросить его помочь подобрать торговую стратегию для вашего советника. Он предложит вам свой вариант. Именно такой вариант мы с вами рассмотрим в данной статье в качестве примера.

Давайте теперь подведем итог вышесказанного и сформируем краткие подпункты, символизирующие возможные пути, по которым мы пойдем при построении нового советника с нуля. Начнем с того, что возможны несколько сценариев начала работы, которые становятся очевидными:

  1. Мы не определились с архитектурой будущего кода и не знаем, с чего начать, а также абсолютно не знаем, какой из подходов к трейдингу нужно выбрать.
  2. Мы не определились с архитектурой будущего кода и не знаем, с чего начать, но знаем примерную картину основного рабочего кода и что мы хотим от советника.
  3. У нас есть готовая архитектура, которая для нас комфортна, но абсолютно не знаем, какой из подходов к трейдингу нужно выбрать.
  4. Мы знаем архитектуру, которую хотим использовать, а также имеем четкое представление о будущей логике торговли советника.

Как правило, все будет сводиться к подобным конструкциям. Ко всем четырем пунктам можно применить общую схему построения любой торговой системы, если мы делаем следующее:

  • Если мы не знаем архитектуру (основной код или каркас), то в первую очередь нужно реализовать его, а после чего реализовывать все, что обеспечивает функционирование данного каркаса.

Это может означать, например, что мы можем попросить реализовать классы, входные переменные, поля и прототипы методов, интерфейсы, а также основной торговый функционал советника, который будет использовать описанные нами сущности. Этот код при грамотном обращении с ChatGPT можно сделать таким образом, чтобы он занимал, скажем, не более 5-10% от общего количества знаков. В таком случае мы сможем быстро реализовать его и после перейти к реализации процедур, которые будут содержать около 90% всего кода. Эти процедуры уже будут реализовываться также просто, ведь их будет очень много, и по размеру они выйдут достаточно маленькими и легко исполнимыми. Конечно, гораздо проще, когда у вас есть готовый шаблон, и вам не нужно мудрить со всем этим, но не у всех есть знания и опыт, подобные моим. Таким людям нужно знать, как и с чего начать.


Разрабатываем торговую систему с помощью ChatGPT

Полагаю, что я дал вам достаточно теоретической информации. Настало время применить наши знания. В моем случае я использую готовый шаблон, на котором строю свои советники. Такой шаблон я описывал в одной из предыдущих статей. Его особенность в том, что он обеспечивает параллельную торговлю множеством инструментов, будучи повешенным лишь на один график. В нем уже реализован весь необходимый торговый функционал и основная архитектура. Я буду строить торговую систему строго по рекомендации ChatGPT. Начать в данной связи я решил с того, что сам реализую основную торговую логику советника, как и визуальную составляющую, потому что это потребует от меня меньше трудозатрат.

Когда вы начнете взаимодействовать с ChatGPT, то поймете, что вы потратите гораздо больше нервов и усилий, пытаясь объяснить ему, что нужно делать, и по сто раз будете корректировать его ответы при реализации некоторых просьб и задач. Через некоторое время вы просто начнете чувствовать, какие вопросы стоит задавать, а какие не стоит, и начнете давать только те задачи, которые в итоге будут экономить ваше время и нервы, а не отнимать. Здесь есть довольно тонкая грань, прочувствовать которую вы должны самостоятельно — другого пути нет. Все познается в практике. Решение о моем подходе к конструированию советника как раз в полной мере обусловлено именно данными соображениями.

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

  1. Открытие позиции на покупку.
  2. Закрытие позиции на покупку.
  3. Открытие позиции на продажу.
  4. Закрытие позиции на продажу.

Для реализации данных предикатов он мне предложил следующую условную логику:

  1. Текущая цена замкнута выше EMA, разница между текущей ценой и EMA меньше ATR * коэффициент, и RSI меньше 30.
  2. Текущая цена замкнута ниже SMA, или текущая цена замкнута выше верхней полосы индикатора Bollinger Bands.
  3. Текущая цена замкнута ниже EMA, разница между текущей ценой и EMA меньше ATR * коэффициент, и RSI больше 70.
  4. Текущая цена замкнута выше SMA, или текущая цена замкнута ниже нижней полосы индикатора Bollinger Bands.

Очевидно, что данные логические условия возвращают истину при успехе и ложь при несоблюдении условия. Этих сигнальных значений вполне достаточно для реализации торговли рыночными ордерами. Здесь я хочу обратить ваше внимание на очевидную возможность модернизации данной логики. Для этого можно сделать следующее:

  • [K1] — зона нижнего значения RSI
  • [K2 = 100 - K1] — зона верхнего значения RSI

Данные выражения можно использовать для расширения гибкости алгоритма, что в последствии положительно повлияет на эффективность оптимизации советника:

  1. Текущая цена замкнута выше EMA, разница между текущей ценой и EMA меньше ATR * коэффициент, и RSI меньше K1
  2. Текущая цена замкнута ниже SMA или текущая цена замкнута выше верхней полосы индикатора Bollinger Bands
  3. Текущая цена замкнута ниже EMA, разница между текущей ценой и EMA меньше ATR * коэффициент, и RSI больше K2
  4. текущая цена замкнута выше SMA или текущая цена замкнута ниже нижней полосы индикатора Bollinger Bands

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

Учитывая, какие условия нужно реализовать, нам потребуется один из двух вариантов реализации следующих индикаторов:

  1. SMA — обычная скользящая средняя (одна линия)
  2. EMA — экспоненциальная скользящая средняя (одна линия)
  3. Bollinger Bands — полосы Боллинджера (совокупность трех линий)
  4. RSI — индекс относительной силы (одна линия в отдельном окне)
  5. ATR — средний истинный диапазон (одна линия в отдельном окне)

Индикаторы можно реализовать, используя специальные предопределенные функции языка MQL5, но мне не нравится подобный подход, потому что код, который будет реализован с помощью данного способа, во-первых, будет труднее конвертировать в MQL4 версию, а во-вторых, мне будет сложнее интегрировать его, например, в свои проекты на других языках, что я делаю очень часто. У меня давно вошло в привычку делать все максимально просто и расчетом на будущее, считаю это очень хорошей привычкой.

Вторым немаловажным моментом является то, что, как правило, подобные индикаторы тащат за собой ненужные и избыточные расчеты и функционал. Кроме того, доработка подобных индикаторов невозможна, так как их функции жестко зафиксированы на уровне кода, и для внесения изменений потребуется создавать свою версию индикатора в любом случае. Думаю, очевидно, что напрашивается вывод о том, что лучше иметь свою реализацию внутри советника или скрипта. Для реализации подобных индикаторов я придумал следующий прием:

  1. Создание массивов для хранения значений линий индикаторов (ограниченное последними N барами).
  2. Реализация сдвига значений массивов при появлении нового бара.
  3. Реализация очистки массива значений индикаторов в случае ошибок или длительного дисконнекта.
  4. Реализация вычисления значения индикатора для последнего бара при его закрытии.

В данном подходе первые три пункта создают общие блоки массивов и функции, которые обеспечивают перечисленные действия. На примере нашей задачи давайте посмотрим, как это будет выглядеть. Начнем с первого пункта:

   double SMA1Values[]; // Массив для хранения значений SMA
   double EMAValues[];  // Массив для хранения значений EMA (экспоненциальная)
   double RSIValues[];  // Массив для хранения значений RSI
   
   double BollingerBandsUpperValues[];  // Массив для хранения значений BollingerBands, верхняя
   double BollingerBandsMiddleValues[]; // Массив для хранения значений BollingerBands, средняя
   double BollingerBandsLowerValues[];  // Массив для хранения значений BollingerBands, нижняя
   
   double ATRValues[];// vассив для хранения значений Average True Range

Данные массивы инициализируются при старте советника с заданными ограничениями длины:

   //Подготовка массивов индикаторов
   void PrepareArrays()
   {
      ArrayResize(SMA1Values, LastBars);
      ArrayResize(EMAValues, LastBars);
      ArrayResize(RSIValues, LastBars);
      ArrayResize(BollingerBandsUpperValues, LastBars);
      ArrayResize(BollingerBandsMiddleValues, LastBars);
      ArrayResize(BollingerBandsLowerValues, LastBars);
      ArrayResize(ATRValues, LastBars);
   }

Так как для стратегии нам не нужно тащить за собой все предшествующие значения, как это делают классические индикаторы, это скорее плюс. Я люблю подобную парадигму построения, потому что она обеспечивает простоту кода и равноценность как стартовых значений индикатора, так и тех, которые получены с помощью предыдущих. Теперь посмотрим, как будет выглядеть сдвиг значений:

   //сдвиг значений индикаторов
   void ShiftValues()
   {
      int shift = 1;
      for (int i = LastBars - 1; i >= shift; i--)
      {
         SMA1Values[i] = SMA1Values[i - shift];
         EMAValues[i] = EMAValues[i - shift];
         RSIValues[i] = RSIValues[i - shift];
         BollingerBandsUpperValues[i] = BollingerBandsUpperValues[i - shift];
         BollingerBandsMiddleValues[i] = BollingerBandsMiddleValues[i - shift];
         BollingerBandsLowerValues[i] = BollingerBandsLowerValues[i - shift];
         ATRValues[i] = ATRValues[i - shift];
      }
   }

Как видно, все крайне просто. То же самое будет касаться и очистки массивов:

   //сброс всех массивов индикаторов, если произошел сбой связи [также можно использовать при инициализации советника]
   void EraseValues()
   {
      for (int i = 0; i < LastBars; i++)
      {
         SMA1Values[i] = -1.0;
         EMAValues[i] = -1.0;
         RSIValues[i] = -1.0;
         BollingerBandsUpperValues[i] = -1.0;
         BollingerBandsMiddleValues[i] = -1.0;
         BollingerBandsLowerValues[i] = -1.0;
         ATRValues[i] = -1.0;
      }
   }

Думаю, не стоит показывать, где данный функционал будет отрабатывать. Я думаю, многие догадаются сами. Теперь давайте переходить к реализации самих индикаторов. Для этого я попросил ChatGPT реализовать соответствующую функцию, которая подходила бы, исходя из моей парадигмы построения кода. Начал я с индикатора "SMA":

   //1 Функция, реализующая вычисление значение индикатора к бару "1"
   double calculateMA(int PeriodMA,int Shift=0)
   {
      int barIndex=Shift+1;//индекс бара для которого считается SMA (со сдвигом)
      int StartIndex=barIndex + PeriodMA-1;//индекс стартового бара для расчета SMA
      if (StartIndex >= LastBars) return -1.0; // Проверка на доступность данных баров для вычисления SMA (если не валид то значение будет равно -1)
      double sum = 0.0;

      for (int i = StartIndex; i >= barIndex; i--)
      {
         sum += Charts[chartindex].CloseI[i];
      }
      LastUpdateDateTime=TimeCurrent();
      return sum / PeriodMA;
   }

Как видно, функция получилась очень простой и короткой. Вид данной функции был изначально немного другой. При первой генерации я нашел множество ошибок в ней, например, связанных с тем, что он неверно понимал, в какую сторону идет нумерация баров относительно времени и так далее. Множество мелких недочетов. Но после определенных манипуляций я исправил все это и дополнительно добавил параметр "Shift", которого не было в изначальной реализации. Наведя красоту, я просил по образу и подобию реализовать остальные индикаторы. После чего в его реализациях было гораздо меньше ошибок. Я просто отправлял следующие просьбы реализовать подобную функцию для другого индикатора, включив в контекст вопроса примеры предыдущих его реализаций. Это сэкономило много времени. Давайте теперь посмотрим на его последующие реализации всех оставшихся индикаторов. Начнем с "EMA":

   //2 Функция, реализующая вычисление значения экспоненциальной скользящей средней (EMA) к бару "1"
   double calculateEMA(int PeriodEMA,double Flatness=2.0,int Shift=0)
   {
      int barIndex = Shift+1; // индекс бара для которого считается EMA (со сдвигом)
      int StartIndex=barIndex + PeriodEMA-1;//индекс стартового бара для расчета первой SMA, для старта рекуррентного вычисления EMA
      if (StartIndex >= LastBars) return -1.0; // Проверка на доступность данных баров для вычисления EMA (если не валид то значение будет равно -1)
   
      double sum = 0.0;
      double multiplier = Flatness / (PeriodEMA + 1); // Весовой множитель
      double prevEMA;
   
      // Вычисление начального значения для EMA (первое значение считается как обычное SMA)
      for (int i = StartIndex; i >= barIndex; i--)
      {
         sum += Charts[chartindex].CloseI[i];
      }
      prevEMA = sum / PeriodEMA;//это и есть стартовое значение к бару (StartIndex-1)
   
      // Применение формулы EMA для оставшихся значений
      for (int i = StartIndex; i >= barIndex; i--)
      {
         prevEMA = (Charts[chartindex].CloseI[i] - prevEMA) * multiplier + prevEMA;
      }
   
      LastUpdateDateTime = TimeCurrent();
      return prevEMA;
   }

Кстати, говоря, исследуя и разбираясь в генерациях ChatGPT, приходится обращаться к различным интернет-ресурсам, чтобы понимать, какой индикатор на основе какой идеи построен, и это делает вас более грамотным. Особенно это видно на примере "EMA". Если внимательно посмотреть на код, он не сильно отличается от более простой реализации "SMA" и, скорее, выглядит надстройкой над обычной скользящей средней. Причем никакой экспоненты тут и в помине нет, хотя в названии индикатора почему-то есть это. Следующий на очереди – индикатор "RSI":

   //3 Функция для расчета RSI к бару "1"
   double calculateRSI(int PeriodRSI,int Shift=0)
   {
       int barIndex = Shift+1; // индекс бара для которого считается RSI (со сдвигом)
       int StartIndex = barIndex + PeriodRSI - 1; // индекс стартового бара для расчета RSI
       if (StartIndex >= LastBars) return -1.0; // Проверка на доступность данных баров для вычисления RSI (если не валид то значение будет равно -1)
   
       double avgGain = 0.0;
       double avgLoss = 0.0;
       double change;
   
       // Вычисление начальных значений для avgGain и avgLoss
       for (int i = StartIndex; i > barIndex; i--)
       {
           change = Charts[chartindex].CloseI[i]-Charts[chartindex].OpenI[i];
           if (change > 0)
           {
               avgGain += change;
           }
           else if (change < 0)
           {
               avgLoss -= change;
           }
       }
   
       avgGain /= PeriodRSI;
       avgLoss /= PeriodRSI;
   
       // Расчет RSI
       double RS = 0.0;
       if (avgLoss != 0)
       {
           RS = avgGain / avgLoss;
       }
   
       double RSI = 100 - (100 / (1 + RS));
   
       LastUpdateDateTime = TimeCurrent();
       return RSI;
   }

Теперь нужно сделать аналогичную процедуру для индикатора "Bollinger Bands". Эта процедура должна возвращать значения трех кривых, которые можно положить в структуру, предварительно подготовив ее:

   //структура для возвращения всех трех линий bollinger bands
   struct BollingerBands 
   {
       double upper;
       double middle;
       double lower;
   };

Теперь, добавив в контекст вопроса данную структуру, можно попросить реализовать функцию с учетом того, что она должна возвращать тип "BollingerBands". С такой задачей он справится без проблем:

   //4 Функция для вычисления Bollinger Bands индикатора
   BollingerBands calculateBollingerBands(int PeriodBB, double DeviationBB,int Shift=0) 
   {
       int barIndex = Shift+1; // индекс бара для которого считается Bollinger Bands (со сдвигом)
       int StartIndex = barIndex + PeriodBB - 1; // индекс стартового бара для расчета первой SMA, для старта рекуррентного вычисления EMA
       BollingerBands rez;
       rez.lower=-1.0;
       rez.middle=-1.0;
       rez.upper=-1.0;
       if (StartIndex >= LastBars) return rez; // Проверка на доступность данных баров для вычисления BB (если не валид то значение будет равно -1)
   
       double sum = 0.0;
       double prevBB;
       double sumSquares = 0.0;
   
       // Вычисление начального значения для BB (первое значение считается как обычное SMA)
       for (int i = StartIndex; i >= barIndex; i--) {
           double closePrice = Charts[chartindex].CloseI[i];
           sum += closePrice;
       }
       prevBB = sum / PeriodBB; //это и есть стартовое значение к бару (StartIndex-1)
   
       // Вычисление стандартного отклонения
       for (int i = StartIndex; i >= barIndex; i--) {
           double closePrice = Charts[chartindex].CloseI[i];
           sumSquares += pow(closePrice - prevBB, 2);
       }
       double standardDeviation = sqrt(sumSquares / PeriodBB);
   
       // Вычисление Bollinger Bands
       double upperBand = prevEMA + DeviationBB * standardDeviation;
       double lowerBand = prevEMA - DeviationBB * standardDeviation;
   
       rez.upper = upperBand;
       rez.middle = prevEMA;
       rez.lower = lowerBand;
   
       LastUpdateDateTime = TimeCurrent();
       return rez;
   }

Осталось реализовать лишь вариант функции для вычисления "ATR":

   //5 Функция для вычисления Average True Range (Relative)индикатора
   double calculateRelativeATR(int PeriodATR,int Shift=0)
   {
       int barIndex = Shift+1; // индекс бара для которого считается ATR (со сдвигом)
       int StartIndex = barIndex + PeriodATR - 1; // индекс стартового бара для расчета первого ATR
       if (StartIndex >= LastBars) return -1.0; // Проверка на доступность данных баров для вычисления ATR и True Range (если не валид то значение будет равно -1)
   
       double sumPrice=0.0;
       double sumTrueRange = 0.0;
       double ATR;
   
       // Вычисление True Range для баров и сумма значений для расчета первого ATR
       for (int i = StartIndex; i >= barIndex; i--)
       {
           sumPrice+=Charts[chartindex].HighI[i]+Charts[chartindex].LowI[i]+Charts[chartindex].CloseI[i]+Charts[chartindex].OpenI[i];//добавленное мной
           double high = Charts[chartindex].HighI[i];
           double low = Charts[chartindex].LowI[i];
           double trueRange = high - low;
           sumTrueRange += trueRange;
       }
   
       // Вычисление ATR
       //ATR = sumTrueRange / PeriodATR; - классический расчет
       ATR = 100.0 * (sumTrueRange / PeriodATR)/(sumPrice/(PeriodATR*4.0));//расчет относительного ATR в процентах
   
       LastUpdateDateTime = TimeCurrent();
       return ATR;
   }

Здесь прошу обратить внимание на закомментированную строчку в конце. Я немного модифицировал данный индикатор, для того чтобы он оперировал относительными величинами. Это нужно для того, чтобы не нужно было задавать для каждого торгового инструмента свои веса, а это будет происходить автоматически, исходя из текущей цены. Это позволит более эффективно проводить мультивалютную оптимизацию. Она нам понадобится для доказательства того факта, что даже такой простейший алгоритм, при правильном использовании, может дать вам небольшой, но достаточный форвард период для торговли. В сочетании с иными приемами эффективности можно сделать данную торговлю вполне приемлемой, даже на том уровне, что сейчас позволяет советник.

Предикаты я реализовал самостоятельно. Это было очень легко. Давайте посмотрим на один из них, скажем, первый:

   //для открытия позиций на покупку
   bool bBuy()
      {
      //определяем есть ли уже открытая позиция
      bool ord;
      ulong ticket;
      bool bOpened=false;
      for ( int i=0; i<PositionsTotal(); i++ )
         {
         ticket=PositionGetTicket(i);
         ord=PositionSelectByTicket(ticket);
         if ( ord && PositionGetInteger(POSITION_MAGIC) == MagicF)
            {
            bOpened=true;
            return false;
            }
         }
         
      if (!bOpened && EMAValues[1] > 0.0)//только если ничего не открыто и индикатор посчитан
         {
         //K - управляющий коэффициент
         //RSIPercentBorder - управляющий RSI
         double Val1=Charts[chartindex].CloseI[1]-EMAValues[1];
         double Val2=ATRValues[1]*(1.0/K);
         if (Val1 > 0 && Val1 < Val2 && RSIValues[1] < RSIPercentBorder) return true;         
         } 
      return false;
      }

Предикат на открытие продажной позиции аналогичен за незначительными исключениями. Предикат на закрытие еще проще:

   //для закрытия позиции на покупку
   bool bCloseBuy()
      {
      if (SMA1Values[1] > 0.0)
         {
         if (Charts[chartindex].CloseI[1] < SMA1Values[1] || Charts[chartindex].CloseI[1] > BollingerBandsUpperValues[1] )
            {
            return true;
            }
         }
      return false;   
      }

Работать все это будет очень просто:

   IndicatorDataRecalculate();//пересчет индикаторов

   if ( bCloseBuy() )
      {
         CloseBuyF();
      }
   if ( bCloseSell() )
      {
         CloseSellF();  
      }
   if ( bBuy() )
      {
         BuyF();
      }
   if ( bSell() )
      {
         SellF();
      } 

По-моему, проще некуда, да и сложнее не нужно. Весь этот код должен выполняться при появлении нового бара. Отдельно я реализовал визуализацию индикаторов. Единственное, что мне не нравится, это то, что такие индикаторы, как "ATR" и "RSI", предназначены для отрисовки в отдельном окне. Для них я сделал свою версию отрисовки, чтобы они также были привязаны к цене, так как отдельное окно не получится создать искусственно, да и, честно говоря, не очень-то они и нужны. Для этого я создал определенную парадигму отрисовки оконных индикаторов.

  1. Введение управляющего значения "Percent" для создания трех коридоров из одного.
  2. Определение максимального (Max) и минимального (Min) значения индикатора по всему массиву сохраненных значений.
  3. Вычисление дельты данного коридора (Delta = Max - Min).
  4. Вычисление верхнего коридора повышенных значений (HighBorder = Max - Delta * Percent / 100).
  5. Вычисление нижнего коридора повышенных значений (LowBorder = Min + Delta * Percent / 100).
  6. Средний коридор уже определен, так как определены и верхний и нижний.

Если текущее значение индикатора лежит в одном из коридоров, то его точки приобретают соответствующий цвет, который соответствует данному коридору. Вот и все, все очень просто. Так мы можем привязать значения к барам графика и, например, просто менять их цвет соответственным образом или просто создавать объекты, сцепленные с баром, которые имеют соответствующий цвет. Как, наверное, заметили многие, я взял идею с индикатора "RSI", потому как для торговли, как раз, именно данная схема и используется обычно. Там эти зоны называются перекупленностью и перепроданностью.

Я думаю, что данный код здесь не так важен, ведь он имеет наименьшее отношение к реализации нашей задачи, а лишь поможет в исправлении возможных ошибок и доработок. При желании, даже эту отрисовку вы сможете реализовать с помощью ChatGPT, если немного включите соображалку. Тем не менее, думаю, стоит показать, как работает данная отрисовка:

Визуализация индикаторов

Здесь все исполнено максимально просто, с помощью одного единственного типа объекта "Линия". Если при создании линии стартовую и конечную точку линии привязать к одному и тому же времени и цене, то линия превращается в точку. Регулируя толщину линии, мы тем самым регулируем жирность соответствующей точки. Это просто некоторые лайфхаки от меня, которые я использую уже очень давно.


Оценка функциональности и анализ результатов

Несмотря на то, что ChatGPT считает данный алгоритм оптимальным, мы не знаем, на основе чего приняты подобные решения. Мерилом эффективности может служить либо хороший бектест, либо реальная торговля. Надеюсь, все понимают, что реальной торговле должна предшествовать оптимальная настройка, которую можно произвести с помощью оптимизатора MetaTrader 5. Благодаря тому, что данный терминал обладает возможностью мультивалютной оптимизации и учитывая возможности моего шаблона, который в полной мере использует эффективность данного инструмента, можно смело оптимизировать советник по всем "28" валютным парам, пожалуй, перечислять их не стоит. Но стоит отметить очевидные преимущества такого подхода:

  1. Автоматический поиск мультивалютных закономерностей
  2. Мультивалютные закономерности имеют больший вес и дальнейшую адаптированность к изменениям рынка
  3. Получается больше трейдов, так как каждый торговый инструмент что-то дает от себя
  4. Экономия времени (потому что не нужно оптимизировать каждый инструмент по отдельности)

Есть, конечно, и минусы. В данном случае самый главный — это невозможность тонкой подстройки под каждый инструмент. Конечно, данная задача может быть решена введением дополнительного функционала, но это не тема данной статьи. Но мало произвести данную оптимизацию, важно еще правильно отбирать результаты из всего скопа, который она вам предлагает. Я отобрал оптимальный:

Оптимальный вариант оптимизации

Как видно, я оптимизировал с "2018" года и по "2023", используя таймфрейм "H4", а все шесть месяцев из "2023" года я оставил для форварда. Как видно, несмотря на не очень красивую кривую прибыли на участке оптимизации, мы получили еще пару-тройку месяцев для прибыльной торговли, а данный факт означает, что стратегия не лишена смысла и имеет потенциал для успешного использования для торговли. Многие торговые системы, которые вы бы оптимизировали, даже к этому результату, скорее всего, не приблизились бы. Порой можно тестировать невероятно крутые системы с точки зрения кода и не получать даже этого.

Да, я бы, конечно, много чего еще сюда добавил в этот алгоритм, и для меня это лишь игрушка. Но стоит сказать, что важно совсем не это, а потенциал расширения полученного советника. Здесь играет роль не столько предложенный алгоритм, а уже вступает в игру ваша компетентность и креативность. Для успешной интеграции в процесс разработки на MQL5 вам потребуются важные качества:

  • Навыки программирования (обязательно)
  • Навыки в математике (желательно)
  • Блоковое мышление
  • Умение упрощать задачу и дробить на части
  • Понимание того факта, что ChatGPT это лишь инструмент, а не волшебник, и не стоит винить его в том, что что-то не работает (все, что не работает, это ваша часть работы, которую вы должны сделать)
  • Правильная интерпретация полученной торговли
  • Осознание того, что ошибки он допускает в любом случае, но вас это не должно беспокоить (главное, что вы достигли выигрыша во времени трудозатрат на разработку)
  • Выработка собственной схемы применения (это не обязательно, конечно, вы можете пользоваться моим подходом)
  • ChatGPT ваш компаньон, сила которого зависит от вас напрямую. Чем терпеливее, умнее и находчивее вы, тем более эффективен этот компаньон.

Если сделать выжимку из всего сказанного, то все зависит от вас напрямую. У вас есть инструмент, которым вы можете либо пользоваться, либо нет, на свое усмотрение, но я могу сказать однозначно, что мне этот инструмент очень пригодился, в том числе для программирования.


Заключение

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

Но я все равно советую попробовать вам данный инструмент и не жалеть своего времени. Как минимум, на примере ChatGPT, вы сможете обрести правильное отношение к искусственному интеллекту и понять, как относиться к подобным технологиям в будущем. Потенциально возможно встраивание данной технологии практически в любую цепочку разработки. Данная технология, можно сказать, первопроходец здесь, и я уверен, что это лишь начало, и очень скоро нас ждут очень быстрые изменения. И советую вам как можно быстрее начинать знакомиться с данным инструментом и пытаться его применять в самых широких спектрах задач.

Прикрепленные файлы |
ChatGPT_bot.set (2.99 KB)
ChatGPT_bot.mq5 (146.69 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (27)
Evgeniy Ilin
Evgeniy Ilin | 13 сент. 2023 в 22:28
Valeriy Yastremskiy #:
Не, улыбнуло просто))) с фантазией ошибка) и в данном случае для текущего символа можно просто _Point) 

Ну да шутку оценил ))). Но не дай бог начнете делать мульти инструмент )))

Dmitry Fedoseev
Dmitry Fedoseev | 14 сент. 2023 в 02:15
Evgeniy Ilin #:

в 10 - 20 раз? А почему не в 50 - 100 ? А может в 100-1000 ? Как это оценивать? Я понимаю о чем вы говорите, но мне даже не интересно тратить свое время на споры об этом

Мозгами, дружище, мозгами оценивать. Т.е. необходимо из наличие, в первую очередь... а там, глядишь, и интерес появится. 

Evgeniy Ilin
Evgeniy Ilin | 16 сент. 2023 в 12:38
Dmitry Fedoseev #:

Мозгами, дружище, мозгами оценивать. Т.е. необходимо из наличие, в первую очередь... а там, глядишь, и интерес появится. 

Вы очень ранимая натура видимо. Возможно я ошибся сделав сколь угодно эмоциональный комментарий.

Yauheni Shauchenka
Yauheni Shauchenka | 2 апр. 2024 в 15:23

Суть статьи можно описать вашей фразой " все, что не работает, это ваша часть работы, которую вы должны сделать" :) 


Пробовали работать с copilot, Евгений @Evgeniy Ilinhttps://www.metatrader5.com/ru/metaeditor/help/development/copilot

Evgeniy Ilin
Evgeniy Ilin | 2 апр. 2024 в 19:13
Yauheni Shauchenka #:

Суть статьи можно описать вашей фразой " все, что не работает, это ваша часть работы, которую вы должны сделать" :) 


Пробовали работать с copilot, Евгений @Evgeniy Ilinhttps://www.metatrader5.com/ru/metaeditor/help/development/copilot

А смысл какой ) это GPT 3.5 который бесплатный. Сейчас это уже мусор практически. А к GPT 4.0  никто вам бесплатно не даст доступ, потому что это стоит денег как минимум. Да и GPT 4.0 я вам так скажу не особо знает mql5. Спасает то что язык этот отпочковался от C++ и имеет сходный синтаксис, потому он и может кое что выдать. По крайней мере некий набросок, который уже дальше можно улучшать. У меня есть доступ к GPT 4.0, копилотом не пользуюсь. А есть нейронки и покруче GPT 4.0 на самом деле, для работы с кодом... ну это так.

Теория категорий в MQL5 (Часть 8): Моноиды Теория категорий в MQL5 (Часть 8): Моноиды
Статья продолжает серию о реализации теории категорий в MQL5. Здесь мы вводим моноиды как домен (множество), который отличает теорию категорий от других методов классификации данных за счет включения правил и элемента равнозначности.
DoEasy. Элементы управления (Часть 32):  горизонтальный "ScrollBar", прокрутка колесиком мышки DoEasy. Элементы управления (Часть 32): горизонтальный "ScrollBar", прокрутка колесиком мышки
В статье завершим разработку функционала объекта-горизонтальной полосы прокрутки. Сделаем возможность прокрутки содержимого контейнера перемещением ползунка полосы прокрутки и вращением колёсика мышки. Также внесём дополнения в библиотеку с учётом появившейся в терминале новой политики исполнения ордеров и новых кодов ошибок времени выполнения в MQL5.
Нейросети — это просто (Часть 48): Методы снижения переоценки значений Q-функции Нейросети — это просто (Часть 48): Методы снижения переоценки значений Q-функции
В предыдущей статье мы познакомились с методом DDPG, который позволяет обучать модели в непрерывном пространстве действий. Однако, как и другие методы Q-обучения, DDPG склонен к переоценки значений Q-функции. Эта проблема часто приводит к обучению агента с неоптимальной стратегией. В данной статье мы рассмотрим некоторые подходы преодоления упомянутой проблемы.
Нейросети — это просто (Часть 47): Непрерывное пространство действий Нейросети — это просто (Часть 47): Непрерывное пространство действий
В данной статье мы расширяем спектр задач нашего агента. В процесс обучения будут включены некоторые аспекты мани- и риск-менеджмента, которые являются неотъемлемой частью любой торговой стратегии.