Знакомство с языком MQL5 (Часть 25): Создание советника для торговли по графическим объектам (II)
Введение
И снова приветствуем вас в Части 25 серии "Знакомство с языком MQL5"! В предыдущей статье мы рассмотрели, как сочетание ручного анализа графиков с автоматизированным исполнением сделок на основе графических объектов помогает преодолеть разрыв между дискреционной и автоматизированной торговлей. Фокусом того проекта были зоны поддержки и сопротивления, нарисованные с помощью инструмента "прямоугольник".
Эта статья является продолжением этой концепции, но на этот раз мы будем использовать трендовые линии. Будучи одними из наиболее широко используемых инструментов в техническом анализе, трендовые линии помогают вам определять направление рынка, а также возможные точки пробоя или разворота. Мы создадим советник, который сможет выявлять объекты трендовых линий на графике и, исходя из состояния рынка, автоматически инициировать сделки, когда цена пробивает эти линии вверх или вниз.
Как работает советник
Советник будет использовать две трендовые линии, которые пользователь вручную нарисует на графике. Одна линия, показывающая нисходящий тренд, проводится от более высокой точки к более низкой, а другая, показывающая восходящий тренд, проводится от более низкой точки к более высокой. Советник будет использовать их имена для выявления соответствующих объектов на графике. При том предполагается, что пользователь введет точные имена трендовых линий во входных настройках советника. Даже когда на графике нарисовано несколько трендовых линий, данная техника дает советнику четкую информацию о том, за какими из них нужно следить.
Кроме того, пользователь сможет указать таймфрейм, который советник должен отслеживать, размер лота, который он хотел бы использовать, и желаемый стиль торговли. В советнике доступно два режима: в первом случае советник обрабатывает условия как разворота, так и пробоя с ретестом в зависимости от того, как цена ведет себя вблизи трендовой линии, а во втором случае (режим разворота) советник открывает сделку, когда цена касается трендовой линии, и отображает сигнал разворота. В режиме пробоя и ретеста советник ожидает, когда цена пробьет трендовую линию, прежде чем открыть сделку.

Для управления торговлей советник автоматически установит уровни стоп-лосса (SL) и тейк-профита (TP) на основе последней закрывшейся свечи.
- Для покупок стоп-лосс будет установлен на минимуме последней закрывшейся свечи.
- Для сделок на продажу стоп-лосс будет установлен на максимум последней закрывшейся свечи.
- Тейк-профит (TP) будет установлен на таком расстоянии от цены входа, которое в четыре раза превышает расстояние между ценой входа и уровнем стоп-лосса.


Выявление трендовых линий
Теперь, когда вы имеете полное представление о том, как советник работает, следующий этап заключается в изучении того, как советник будет распознавать трендовые линии на графике. Советнику нужен простой метод для различения линий, которые указывают на восходящий и нисходящий тренд, поскольку его действия зависят от трендовых линий, нарисованных пользователем.
Для этого будут использоваться имена трендовых линий. Для поиска объектов на графике советник будет использовать имена, которые пользователь вводит во входных настройках. Сопоставляя имена, советник сможет с точностью определить каждую из трендовых линий на графике и отслеживать ее позицию в реальном времени. Советник будет реагировать только на те трендовые линии, которые указал пользователь, даже если график содержит другие линии или иллюстрации.
Пример:input string down_trend = ""; // Down Trend Line input string up_trend = ""; // Up Trend Line ulong chart_id = ChartID(); //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true); ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true); }
Пояснение:
Советнику нужна информация о нужных трендовых линиях на графике, прежде чем он сможет их распознать и совершать над ними действия. Для этого мы разработали опции ввода, которые позволяют пользователю ввести имена двух трендовых линий. Одна линия будет использоваться для обозначения нисходящего тренда, в то время как другая будет символизировать рост. Даже при наличии многочисленных других объектов рисования или меток эта техника именования поможет советнику точно определять, какие объекты на графике он должен обрабатывать.

Советнику также необходимо сообщить график, на котором он будет работать. Каждый график в MetaTrader 5 имеет специальный номер для идентификации – идентификатор графика. Получив этот идентификатор, советник будет гарантированно взаимодействовать только с соответствующим графиком и его элементами.
Важным элементом этой схемы является продление трендовых линий вправо. Благодаря этой модификации трендовые линии могут продолжаться в область будущих цен и выходить за пределы своих якорных точек. Это важнейший этап, поскольку он позволяет советнику выявлять взаимодействия цены с трендовыми линиями даже после формирования новых свечей. Без этого расширения линии обрывались бы на своих якорных точках, что сделало бы невозможным обнаружение советником последующих пробоев или разворотов. По мере изменения рынка, продление линий за пределы якорных точек гарантирует надежное распознавание сигналов и непрерывный мониторинг.

Получение свечных данных и данных объекта нисходящей трендовой линии
Чтобы советник мог проанализировать, как цена движется вблизи трендовых линий, следующим шагом является получение как свечных данных, так и данных о трендовых линиях. Сначала советник скопирует свечные данные последних пяти свечей графика. Вы можете определить, возможен ли пробой или разворот, основываясь только на этих недавних свечах.
После получения свечных данных советник также соберет данные трендовой линии в пределах того же пятисвечного диапазона. Он будет обращать внимание только на цены трендовой линии, которые соответствуют по времени этим недавним свечам, а не на якорные точки. Таким образом, советник сможет сравнить текущие движения свечей с точными ценовыми уровнями трендовых линий на том же таймфрейме.
Советник может выявлять, когда цена пробивает трендовую линию вверх, вниз или разворачивается от нее, анализируя корреляцию между ценами трендовой линии и последними пятью свечами. Эта техника гарантирует, что советник будет реагировать только на недавние и актуальные рыночные движения, и улучшает точность процесса обнаружения.
Аналогия
Представьте советника как бдительного сторожевого пса на рынке, который, подобно детективу, исследует место преступления. Каждая свеча представляет собой то, что произошло в контексте цены в определенный момент, подобно фотографии. Трендовая линия, напротив, обозначает значимые границы и напоминает веревку, натянутую над графиком.
Советник рассматривает каждую свечу по отдельности, уделяя особое внимание последним пяти. Он изучает свойства каждой свечи, а также точное положение трендовой линии в этот конкретный момент. Эта процедура похожа на одновременное рассмотрение двух фотографий, одна из которых показывает движение свечи, а другая – расположение трендовой линии во время этого движения.
Советник начинает свой анализ после сбора этих данных. Он задается, например, такими вопросами: касался ли максимум или минимум свечи трендовой линии? Цена стала выше или ниже линии, когда свеча ее пересекла? Свеча были бычьей или медвежьей?
Аналогично тому, как трейдер визуально проверяет график, чтобы увидеть, когда цена касается линии или пробивает ее, советник может понять, как свеча взаимодействовала с трендовой линией, сравнивая эти два элемента информации.
Пример:input string down_trend = ""; // Down Trend Line input string up_trend = ""; // Up Trend Line input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT; // TIME FRAME ulong chart_id = ChartID(); double close_price[]; double open_price[]; double low_price[]; double high_price[]; datetime time_price[]; double td_line_value; double td1_line_value; double td2_line_value; double td3_line_value; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- ArraySetAsSeries(close_price, true); ArraySetAsSeries(open_price, true); ArraySetAsSeries(low_price, true); ArraySetAsSeries(high_price, true); ArraySetAsSeries(time_price, true); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true); ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true); CopyOpen(_Symbol, time_frame, 1, 5, open_price); CopyClose(_Symbol, time_frame, 1, 5, close_price); CopyLow(_Symbol, time_frame, 1, 5, low_price); CopyHigh(_Symbol, time_frame, 1, 5, high_price); CopyTime(_Symbol, time_frame, 1, 5, time_price); //DOWN TREND td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0); td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0); td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0); td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0); }
Пояснение:
На этом начальном этапе программа устанавливает временной диапазон, в котором она будет работать, и готовится к хранению информации о свечах в пустых контейнерах. Впоследствии в этих контейнерах будут сохранены цены открытия, закрытия, максимума и минимума каждой свечи, а также точный момент появления свечи на графике. Еще до начала анализа эта конфигурация гарантирует, что программа сможет получить полные и хорошо структурированные ценовые данные с рынка.
double td_line_value; double td1_line_value; double td2_line_value; double td3_line_value;
На этом этапе создается пространство хранения для размещения числовых данных, которые показывают расположение трендовой линии в определенные моменты времени. Компьютер будет использовать эти цифры для сравнения движения рыночной цены с нисходящей линией графика. Затем контейнеры организуются так, чтобы самая свежая информация отображалась первой. Компьютер теперь сможет легче анализировать недавнюю рыночную активность, поскольку сможет мгновенно получать доступ к недавним свечам, минуя необходимость сортировать старые данные. Кроме того, все контейнеры должны быть правильно расположены перед получением рыночных цен.
Программа затем собирает информацию о последних пяти свечах. Она собирает цены этих свечей, а также время, в которое они появились на графике. Программа может отслеживать движения цены вблизи трендовой линии и определять, развивается ли пробой или паттерн разворота, на основе этой короткой последовательности свечей.
td_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[0], 0); td1_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[1], 0); td2_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[2], 0); td3_line_value = ObjectGetValueByTime(chart_id, down_trend, time_price[3], 0);
Каждая линия получает ценовое значение трендовой линии на момент формирования определенной свечи. Через первый параметр, который также указывает название объекта (в данном случае линии нисходящего тренда), функция получает указание, какой график следует исследовать, а через второй параметр – точное время для проверки (соответствующее формированию каждой свечи), а также окно графика (где 0 обозначает основной ценовой график).
Проще говоря, эта функция проверяет, где находилась трендовая линия в момент появления каждой из свечей. Затем советник может сравнить максимум, минимум или цену закрытия свечи с положением трендовой линии, так как он возвращает ценовой уровень трендовой линии на соответствующий момент. Это помогает выявлять ситуации пробоя или разворота, позволяя определить, касалась ли свеча трендовой линии и пересекала ли ее.
Выявление разворота от нисходящей трендовой линии
Следующим этапом является нахождение разворота от нисходящей трендовой линии, который указывает на возможность продажи. В данном случае советник будет следить за взаимодействием между нисходящей трендовой линией и недавними свечами. Советник определит, закрывается ли свеча ниже линии, сигнализируя о потенциальном развороте, когда цена приближается к линии или касается ее. Это поведение является возможным признаком для продажи, так как оно указывает на то, что продавцы снова приобретают контроль над рынком.
Но важно избегать чрезмерной торговли или дублирования сигналов. Прежде чем сделать это, советник сначала проверяет, что в течение последних нескольких баров не было недавних торговых сигналов. Это гарантирует, что программа будет реагировать только на новые сетапы, и предотвращает открытие избыточных или ненужных сделок в рамках одного и того же короткого периода времени.
Пример:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- ObjectSetInteger(chart_id,down_trend,OBJPROP_RAY_RIGHT,true); ObjectSetInteger(chart_id,up_trend,OBJPROP_RAY_RIGHT,true); CopyOpen(_Symbol, time_frame, 1, 5, open_price); CopyClose(_Symbol, time_frame, 1, 5, close_price); CopyLow(_Symbol, time_frame, 1, 5, low_price); CopyHigh(_Symbol, time_frame, 1, 5, high_price); CopyTime(_Symbol, time_frame, 1, 5, time_price); //DOWN TREND td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0); td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0); td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0); td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0); bool prev_touch_down = false; if((high_price[1] > td1_line_value && close_price[1] < open_price[1]) || (high_price[2] > td2_line_value && close_price[2] < open_price[2]) ) { prev_touch_down = true; } int no_bars_down = 0; for(int i = 0; i <= 3; i++) { if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0)) { for(int j = i; j >= 0; j--) { if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0)) { no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent()); break; } } break; } } }
Пояснение:
bool prev_touch_down = false; if((high_price[1] > td1_line_value && close_price[1] < open_price[1]) || (high_price[2] > td2_line_value && close_price[2] < open_price[2]) ) { prev_touch_down = true; }
В первой строке переменная инициализируется значением false. Эта переменная служит маркером, указывающим на то, что недавно появилась медвежья свеча вслед за действительным касанием линии нисходящего тренда. Поскольку такое условие не было найдено в начале, флаг по-прежнему имеет значение false. Суть в том, что эта переменная будет обновлена на true после того, как система подтвердит медвежью реакцию на трендовую линию. Эта переменная может быть использована для управления дальнейшими торговыми действиями, включая избегание множественных или повторяющихся сигналов на продажу в течение короткого периода времени.
Условие в операторе if проверяет две последние свечи, чтобы увидеть, удовлетворяет ли хотя бы одна из них условиям разворота. (high_price[1] > td1_line_value && close_price[1] < open_price[1]) – это первая часть условия, которая рассматривает свечу, закрывшуюся сразу перед текущей. Это условие определяет, пересекла ли вершина свечи трендовую линию в тот момент, что означало бы, что цена коснулась или незначительно проникла за линию. Затем свеча подтверждается как медвежья, если она закрылась ниже, чем открылась. Чтобы протестировать трендовую линию, покупатели могли поднять цену выше, но продавцы снова заполучили контроль и опустили рынок, оставив за собой выше фитиль отскока.
Второй раздел рассматривает свечу за два бара до текущей назад, чтобы зафиксировать предыдущие отскоки. Отскок считается действительным, если одна из двух свечей удовлетворяет критериям отскока.
Код, заключенный в фигурные скобки, изменяет значение флага на true, когда условие оценивается как истинное. Согласно этому отчету, рынок уже отреагировал негативно на нисходящую трендовую линию. Этот флаг можно использовать в качестве предохранителя в последующих разделах программы, чтобы предотвращать избыточную торговлю и гарантировать, что повторные касания в одной и той же области не будут приводить к генерации системой дополнительных сигналов на продажу.
Наконец, этот блок кода помогает в нахождении действительного сигнала разворота от нисходящей трендовой линии. Подтверждением этого считается ситуация, когда свеча приближается к трендовой линии снизу, касается ее и закрывается как медвежья. Выявляя это поведение и отмечая его флагом, программа закладывает основу для более дисциплинированного исполнения сделок. Таким образом, медвежьи развороты подтверждаются только тогда, когда движение цены явно нарушает трендовую линию, при этом избыточные повторные сигналы избегаются.
int no_bars_down = 0; for(int i = 0; i <= 3; i++) { if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0)) { for(int j = i; j >= 0; j--) { if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0)) { no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent()); break; } } break; } }
Строка int no_bars_down = 0; используется для инициализации счетчика нулем в начале кода. Этот счетчик впоследствии будет фиксировать количество баров, которые прошли с момента последнего действительного касания трендовой линии и отскока от нее. Цикл рассматривает последние четыре свечи, чтобы проверить, остается ли цена открытия ниже трендовой линии, и пересек ли ее максимум каждой свечи. Это облегчает обнаружение свечей, которые контактировали с трендовой линией снизу, что является первым признаком потенциального разворота.
После обнаружения такой свечи программа смотрит назад, чтобы найти первую свечу, которая закрывается ниже трендовой линии и является медвежьей. Этот этап подтверждает потенциальный сигнал на продажу, подтверждая, что рынок отскочил от трендовой линии. Программа определяет количество баров, прошедших с момента подтверждающей свечи до настоящего момента. Это количество помогает избежать повторяющихся или дублирующих алертов. Отслеживая количество баров с момента последнего действительного отскока, советник гарантирует, что приниматься во внимание будут только свежие торговые возможности после того, как произошло достаточное движение на рынке. Это значительно уменьшает избыточную торговлю.
Добавление условий входа
Следующим этапом является добавление условия входа в сделку на продажу. Советник теперь может указать точные обстоятельства, при которых он откроет позицию после проверки того, что произошел разворот от нисходящей трендовой линии, и что в недавнем времени не генерировалось каких-либо сигналов. Чтобы убедиться, что только сделки инициируются только действительными сетапами, необходимо проверять одновременно и контакт с трендовой линией, и подтверждение медвежьей свечи, и количество баров, прошедших с момента последнего сигнала. Советник сможет входить в рынок методично и предотвращать избыточную торговлю благодаря этим правилам входа, которые гарантируют, что каждая сделка будет соответствовать паттерну разворота на графике.
Пример:
#include <Trade/Trade.mqh> CTrade trade; int MagicNumber = 53217;
datetime lastTradeBarTime = 0; double ask_price; double take_profit;
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- ArraySetAsSeries(close_price, true); ArraySetAsSeries(open_price, true); ArraySetAsSeries(low_price, true); ArraySetAsSeries(high_price, true); ArraySetAsSeries(time_price, true); trade.SetExpertMagicNumber(MagicNumber); //--- return(INIT_SUCCEEDED); }
ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK); datetime currentBarTime = iTime(_Symbol, time_frame, 0); if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value) || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value)) && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value) && (no_bars_down < 3) && prev_touch_down == false && (currentBarTime != lastTradeBarTime) ) { take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4)); trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit); lastTradeBarTime = currentBarTime; }
Пояснение:
Стандартная торговая библиотека языка MQL5 включена в первой строке: #include <Trade/Trade.mqh>. Эта библиотека предоставляет советнику функции и классы, необходимые для проведения сделок, изменения ордеров и поддержания позиций. Для методичного и безопасного размещения ордеров советник будет использовать экземпляр объекта trade, созданного строкой CTrade trade;.
int MagicNumber = 53217; определяет магическое число. Это специальное число, которое присваивается каждой сделке, которую открывает этот советник. Благодаря SetExpertMagicNumber (MagicNumber) советник может отличать свои сделки от ручных сделок или сделок, открытых другими советниками. Это необходимо, чтобы впоследствии управлять позициями, изменять их или закрывать, не затрагивая другие сделки.
Входная переменная double lot_size = 0.6; используется для определения размера сделки. Это позволяет пользователю изменять размер каждой сделки прямо во входных настройках. Переменная datetime currentBarTime = iTime(_Symbol, time_frame, 0); сохраняет время самой свежей свечи, а переменная ask_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); получает текущую рыночную цену Ask. С помощью этих значений выполняются установка цены входа, определение тейк-профита и предотвращение множественных сделок на одной и той же свече.
(high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value) || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value)
Эта строка определяет, коснулись ли какие-либо из недавних свечей нисходящей трендовой линии или может даже немного пересекли ее. К примеру, условие (high_price[1] >= td1_line_value && open_price[1] < td1_line_value) подтверждает, что максимум предыдущей свечи был выше трендовой линии, но ее цена открытия находилась ниже нее. Это свидетельствует о приближении цены к трендовой линии и возможной ситуации разворота, которую оно создало. Свеча два бара назад, свеча три бара назад и текущая свеча проходят аналогичные проверки. Благодаря использованию логического оператора OR ("или") условие гарантированно выполнится, если любая из указанных свечей удовлетворяет данному требованию.
Условие, подтверждающее окончательный медвежий отскок, было добавлено посредством анализа как текущей, так и предыдущих свечей. Указывая на то, что продавцы набрали силу, и что моментум снижается, это гарантирует, что последняя свеча закрывается ниже трендовой линии. Более того, чтобы считаться медвежьей, свеча должна закрыться ниже своего открытия. Чтобы структура цены оставалась стабильной, а сигнал разворота был более точным, предыдущая свеча также должна открываться ниже трендовой линии.
Это требование гарантирует, что самая свежая свеча подтверждает медвежий разворот. Это подтверждает, что свеча закрылась ниже трендовой линии, указывая на спад моментума и переход контроля к продавцам. Медвежье давление подтверждается, когда свеча закрывается ниже своего открытия. Кроме того, чтобы считалось, что предыдущая свеча поддержала устойчивый нисходящий паттерн, необходимо, чтобы ее открытие было ниже трендовой линии. Вместе эти условия помогают предотвратить ложные входы, вызванные временными свингами цен, и увеличивают достоверность разворотных сигналов.
Сравнивая время текущей свечи со временем последней выполненной сделки, условие (currentBarTime!= lastTradeBarTime) гарантирует, что советник не будет открывать несколько сделок на одной и той же свече, тем самым разрешая только один вход на бар. Советник определяет тейк-профит, как только все требования для входа будут выполнены, умножая абсолютную разницу между текущей ценой Ask и максимумом подтверждающей свечи на четыре, чтобы обеспечить благоприятное соотношение риска к вознаграждению.
Затем, используя заданный размер лота, символ, цену входа, стоп-лосс на максимуме подтверждающей свечи и рассчитанный тейк-профит, он исполняет сделку на продажу. Чтобы обеспечить дисциплинированное и методичное выполнение сделок, после размещения сделки советник обновляет lastTradeBarTime до времени текущей свечи. Это предотвращает множественные сделки на одном и том же баре.
Затем советник должен принять решение, торговать ему пробой с ретестом или простой разворот. Хотя мы до сих пор рассматривали только ситуацию с разворотом от нисходящей трендовой линии, вы можете увидеть, как советник определяет действительный сигнал разворота, рассматривая условия, которые мы только что обсудили. Как только логика разворота будет полностью воссоздана, эту концепцию можно несколько изменить для обработки пробоев с ретестом.
Пример:
input string down_trend = ""; // Down Trend Line input string up_trend = ""; // Up Trend Line input ENUM_TIMEFRAMES time_frame = PERIOD_CURRENT; // TIME FRAME input double lot_size = 0.6; // LOT SIZE enum line_type { reversal = 0, //REVERSAL break_out = 1, //BREAK-OUT reverse_break = 2 // REVERSAL AND BREAK-OUT }; input line_type line_exe = reversal; // MODE
if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value) || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value)) && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value) && (no_bars_down < 3) && prev_touch_down == false && (currentBarTime != lastTradeBarTime) && (line_exe == reversal || line_exe == reverse_break) ) { take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4)); trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit); lastTradeBarTime = currentBarTime; }
Вывод:

Выявление пробоя и ретеста нисходящей трендовой линии
Прежде чем исполнить сделку на покупку по сетапу пробоя и ретеста, советник сначала ждет, чтобы свеча закрылась советник выше линии нисходящего тренда, что укажет на пробой предыдущего уровня сопротивления. Однако советник не начинает торговать сразу. Он ожидает ретеста, при котором цена возвращается к пробитой трендовой линии и касается ее, что указывает на то, что уровень, который ранее был сопротивлением, теперь служит поддержкой.
После подтверждения ретеста советник ищет бычью свечу, которая следует за касанием. Это бычье подтверждение дает нам точку входа и показывает, что покупатели одерживают верх. Советник инициирует ордер на покупку, когда выполнены три критерия: пробой, касание в рамках ретеста и подтверждающая бычья свеча. Благодаря проверке, что сделки совершаются только после подтверждения пробоя движением цены, эта стратегия помогает предотвратить слишком ранний вход и снижает вероятность ложных пробоев.
Пример:
td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0); td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0); td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0); td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0); bool prev_touch_down = false; if((high_price[1] > td1_line_value && close_price[1] < open_price[1]) || (high_price[2] > td2_line_value && close_price[2] < open_price[2]) ) { prev_touch_down = true; } int no_bars_down = 0; for(int i = 0; i <= 3; i++) { if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0)) { for(int j = i; j >= 0; j--) { if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0)) { no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent()); break; } } break; } } //DOWN TREND td_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[0],0); td1_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[1],0); td2_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[2],0); td3_line_value = ObjectGetValueByTime(chart_id,down_trend,time_price[3],0); bool prev_touch_down = false; if((high_price[1] > td1_line_value && close_price[1] < open_price[1]) || (high_price[2] > td2_line_value && close_price[2] < open_price[2]) ) { prev_touch_down = true; } int no_bars_down = 0; for(int i = 0; i <= 3; i++) { if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0)) { for(int j = i; j >= 0; j--) { if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0)) { no_bars_down = Bars(_Symbol,time_frame,time_price[j],TimeCurrent()); break; } } break; } ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK); datetime currentBarTime = iTime(_Symbol, time_frame, 0); if(((high_price[1] >= td1_line_value && open_price[1] < td1_line_value) || (high_price[2] >= td2_line_value && open_price[2] < td2_line_value) || (high_price[3] >= td3_line_value && open_price[3] < td3_line_value) || (high_price[0] >= td_line_value)) && (close_price[0] < td_line_value && close_price[0] < open_price[0] && open_price[1] < td1_line_value) && (no_bars_down < 3) && prev_touch_down == false && (currentBarTime != lastTradeBarTime) && (line_exe == reversal || line_exe == reverse_break) ) { take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4)); trade.Sell(lot_size,_Symbol,ask_price, high_price[0], take_profit); lastTradeBarTime = currentBarTime; } // DOWNTREND BREAKOUT AMD RETEST bool prev_touch_break_out_down = false; if((low_price[1] < td1_line_value && close_price[1] > open_price[1]) || (low_price[2] < td2_line_value && close_price[2] > open_price[2] && open_price[2] > td2_line_value)) { prev_touch_break_out_down = true; } int no_bars_down_breakout = 0; for(int i = 0; i <= 3; i++) { if(low_price[i] < ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0) && open_price[i] > ObjectGetValueByTime(chart_id, down_trend, time_price[i], 0)) { for(int j = i; j >= 0; j--) { if(close_price[j] > open_price[j] && close_price[j] > ObjectGetValueByTime(chart_id, down_trend, time_price[j], 0)) { no_bars_down_breakout = Bars(_Symbol, time_frame, time_price[j], TimeCurrent()); break; } } break; } } if( ((low_price[0] < td_line_value && open_price[0] > td_line_value) || (low_price[1] < td1_line_value && open_price[1] > td1_line_value) || (low_price[2] < td2_line_value && open_price[2] > td2_line_value) || (low_price[3] < td3_line_value && open_price[3] > td3_line_value)) && (close_price[0] > open_price[0]) && close_price[0] > td_line_value && (no_bars_down_breakout < 3) && (prev_touch_break_out_down == false) && (currentBarTime != lastTradeBarTime) && (line_exe == break_out || line_exe == reverse_break) ) { take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4)); trade.Buy(lot_size, _Symbol, ask_price, low_price[0], take_profit); lastTradeBarTime = currentBarTime; }
Пояснение:
В начальной секции кода определяется булев флаг для мониторинга того, произошел ли недавно пробой с ретестом на нисходящей трендовой линии. С помощью этого флага советник может предотвратить повторное генерирование сделок на основе одного и того же сетапа. Следующее требование определяет, начался ли уже сценарий пробоя, анализируя последние несколько свечей.
Кроме того, оно проверяет, открылась ли свеча выше трендовой линии, чтобы подтвердить, что цена совершила пробой и ретест трендовой линии. Чтобы предотвратить слишком частое открытие советником нескольких сделок, счетчик считает количество баров с момента последнего пробоя, а также устанавливается флаг, сигнализирующий, что касание пробоя уже произошло.
Затем определяется точка пробоя путем итерации по недавним свечам в основном цикле. Сначала выполняется поиск свечи, в которой цена открытие была выше трендовой линии, а цена минимума – ниже нее. Это указывает на первое проникновение трендовой линии, которое является предвестником пробоя. После обнаружения такой свечи вложенный цикл проверяет предыдущие свечи в поисках ближайшей свечи, которая закрывается выше трендовой линии и является бычьей. Это демонстрирует, что трендовая линия фактически превратилась из сопротивления в поддержку, и что пробой является действительным. После получения этого подтверждения оба цикла прерываются, чтобы избежать ненужных дополнительных проверок, и счетчик корректируется, отражая количество баров с момента пробоя.
Данная процедура для пробоя и ретеста значительно отличается от процедуры для разворота. При развороте советник ищет медвежью свечу, которая касается трендовой линии снизу, чтобы выявить отскок. Стратегия пробоя и ретеста включает в себя ожидание советником пробития нисходящей трендовой линии вверх, за которым следуют ретест и бычья свеча, подтверждающая тренд. Сетап пробоя подходит для сделок, которые следуют за подтвержденным изменением в направлении рынка, поскольку акцент делается на нарастании моментума после пробоя трендовой линии, а не на попытках поймать отскок цены.
if( ((low_price[0] < td_line_value && open_price[0] > td_line_value) || (low_price[1] < td1_line_value && open_price[1] > td1_line_value) || (low_price[2] < td2_line_value && open_price[2] > td2_line_value) || (low_price[3] < td3_line_value && open_price[3] > td3_line_value)) && (close_price[0] > open_price[0]) && close_price[0] > td_line_value && (no_bars_down_breakout < 3) && (prev_touch_break_out_down == false) && (currentBarTime != lastTradeBarTime) && (line_exe == break_out || line_exe == reverse_break) ) { take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4)); trade.Buy(lot_size, _Symbol, ask_price, low_price[0], take_profit); lastTradeBarTime = currentBarTime; }
Первая секция условия определяет, произошел ли пробой нисходящей трендовой линии. Она проверяет недавние свечи, чтобы определить, имела ли какая-либо из них цену открытия выше трендовой линии и минимум, который упал ниже нее. Такая ситуация указывает на возможный пробой, так как свеча пробила трендовую линию сверху. Данный механизм предоставляет отложенные подтверждения, гарантируя, что советник будет искать пробойные касания на трех предыдущих свечах в дополнение к текущей.
Далее идет условие (close_price[0] > open_price[0]). Если условие && close_price[0] > td_line_value истинно, это означает, что текущая свеча бычья и закрылась выше трендовой линии. Тот факт, что покупатели контролируют ситуацию, а трендовая линия фактически превратилась из уровня сопротивления в уровень поддержки, служит подтверждением пробоя.
Отслеживая количество баров с момента последнего подтвержденного сетапа, программа гарантирует, что новые сделки не будут совершаться слишком близко к предыдущему пробою. Это позволяет советнику сосредоточиться на новых возможностях и воздерживаться от чрезмерной торговли. Проверяя, что в недавнем времени еще не был зафиксировано пробоев, программа также избегает дублирования сделок на основе одного и того же ценового действия. Наконец, программа проверяет, что на текущем баре еще не было открыто сделок, обеспечивая выполнение только одной сделки за свечу.
Затем проверяется, что советник находится в режиме, который позволяет проводить сделки на пробой, либо отдельно, либо с разворотами. Используя благоприятное соотношение риска к вознаграждению, советник рассчитывает тейк-профит на основе расстояния между текущей ценой и минимумом подтверждающей свечи, как только все требования к сделке будут выполнены. После этого советник исполняет покупку с указанным размером лота, устанавливает рассчитанный тейк-профит, ставит стоп-лосс на минимум пробойной свечи и записывает время сделки в лог, чтобы избежать повторных входов на одной и той же свече.
Вывод:

Выявление разворота от восходящей трендовой линии
Следующим шагом после изучения того, как распознавать сетапы пробоя с ретестом и разворотные сетапы у нисходящей трендовой линии, является поиск потенциальных разворотов от восходящей трендовой линии. Процесс для восходящего тренда в основном противоположен процессу для нисходящего тренда. Трендовая линия здесь является поддержкой, а не на сопротивлением. Когда минимум недавней свечи касается или приближается к восходящей трендовой линии, и бычья свеча закрывается выше своего открытия, это является действительным сигналом разворота. Это указывает на потенциальную возможность покупки, так как показывает, что цена протестировала уровень поддержки, и покупатели начинают набирать позиции.
Чтобы избежать совершения нескольких сделок на основании одного и того же теста уровня поддержки, советник следит за тем, чтобы в недавнем времени не было сгенерировано сигналов, как и для разворотов от нисходящей трендовой линии. Сравнение времени текущей свечи со временем последней сделки также обеспечивает, что будет разрешена только одна сделка за свечу. Советник может последовательно управлять рисками и избегать чрезмерной торговли, методично выявляя развороты от восходящей трендовой линии, по сути воспроизводя логику разворота от нисходящей трендовой линии.
Пример:
double t_line_value; double t1_line_value; double t2_line_value; double t3_line_value;
// UP TREND t_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[0],0); t1_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[1],0); t2_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[2],0); t3_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[3],0); int no_bars_up = 0; for(int i = 0; i <= 3; i++) { if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) && open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0)) { for(int j = i; j >= 0; j--) { if(close_price[j] > open_price[j] && close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0)) { no_bars_up = Bars(_Symbol, time_frame, time_price[j], TimeCurrent()); break; } } break; } } bool prev_touch_up = false; if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) || (low_price[2] < t2_line_value && close_price[2] > open_price[2])) { prev_touch_up = true; // Flag that a recent touch already occurred } if( ((low_price[0] < t_line_value && open_price[0] > t_line_value) || (low_price[1] < t1_line_value && open_price[1] > t1_line_value) || (low_price[2] < t2_line_value && open_price[2] > t2_line_value) || (low_price[3] < t3_line_value && open_price[3] > t3_line_value)) && (close_price[0] > open_price[0]) && close_price[0] > t_line_value && (no_bars_up < 3) && prev_touch_up == false && (currentBarTime != lastTradeBarTime) && (line_exe == reversal || line_exe == reverse_break) ) { take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4)); trade.Buy(lot_size, _Symbol, ask_price, low_price[0],take_profit); lastTradeBarTime = currentBarTime; }
Пояснение:
Значения восходящей трендовой линии на момент каждой из недавних свечей хранятся в переменных, которые инициализируются в первом разделе кода. Советник может оценивать ценовую активность относительно трендовой линии в разные моменты времени, поскольку каждая переменная связана с отдельной свечой. Это гарантирует, что советник сможет отслеживать четыре последние свечи, и это крайне важно для выявления взаимодействий между ценой и трендовой линией.
На следующем этапе извлекаются точные значения трендовой линии для последних нескольких свечей. Получая ценовое значение линии на момент каждой из свечей, советник может точно определить, касался ли минимум свечи восходящей трендовой линии и проникал ли он за нее, что является первым предварительным условием разворота от восходящей трендовой линии.
Затем инициализированный счетчик отслеживает количество баров с момента последнего проверенного сетапа разворота. При выявлении свечи, которая может указывать на тест поддержки, советник проходит по недавним свечам, пока минимум одной из них не окажется ниже трендовой линии, а цена открытия при этом должна быть выше нее. Чтобы подтвердить, что покупатели перехватывают инициативу, вложенный цикл ищет следующую свечу, которая закрывается бычьей и выше трендовой линии. Чтобы избежать повторяющихся алертов в течение короткого промежутка времени, счетчик обновляется, чтобы отразить количество баров с момента подтверждения.
Далее, объявляется булев флаг, показывающий, касалась ли цена трендовой линии в недавнем времени. Советник анализирует последние несколько свечей, чтобы определить, закрылась ли какая-либо из них бычьей после снижения ниже трендовой линии. Чтобы убедиться, что на основе одного и того же ценового взаимодействия не будет совершено несколько сделок, флагу присваивается значение true, если такая свеча существует.
Наконец, перед размещением ордера на покупку, советник учитывает ряд факторов. Он проверяет, что текущая свеча бычья и закрывается выше трендовой линии, что в недавнем времени не было касаний, вызвавших сделку, что на текущей свече еще не исполнялось сделок, что режим исполнения допускает разворотные сделки, и что одна из недавних свечей коснулась трендовой линии или проникла за нее.
Если все эти условия выполнены, советник рассчитывает тейк-профит на основе расстояния, равного расстоянию между ценой Ask и минимумом подтверждающей свечи, умноженному на определенный коэффициент, обеспечивающий благоприятное соотношение риска к вознаграждению. После этого советник применяет тейк-профит, исполняет сделку на покупку, изменяет время последней сделки, чтобы избежать множественных сделок на одной свече, и устанавливает стоп-лосс на минимум разворотной свечи.
Выявление пробоя с ретестом на восходящей трендовой линии
Теперь, ознакомившись с темой разворотов от восходящей трендовой линии, мы перейдем к выявлением потенциальных пробоев с ретестом на восходящей трендовой линии. В данном случае свеча, падающая ниже трендовой линии, подтверждает пробой, указывая на то, что поддержка была нарушена. Советник ожидает ретеста после этого пробоя, который происходит, когда максимум последующей свечи вновь пересекает трендовую линию. Этот ретест показывает, что сломанная поддержка теперь выступает в качестве сопротивления. После того как этот ретест будет подтвержден, советник начнет искать медвежью свечу, которая даст сигнал на открытие сделки на продажу, что будет означать, что продавцы перехватили инициативу.
Пример:// UP TREND t_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[0],0); t1_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[1],0); t2_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[2],0); t3_line_value = ObjectGetValueByTime(chart_id,up_trend,time_price[3],0); int no_bars_up = 0; for(int i = 0; i <= 3; i++) { if(low_price[i] < ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0) && open_price[i] > ObjectGetValueByTime(chart_id, up_trend, time_price[i], 0)) { for(int j = i; j >= 0; j--) { if(close_price[j] > open_price[j] && close_price[j] > ObjectGetValueByTime(chart_id, up_trend, time_price[j], 0)) { no_bars_up = Bars(_Symbol, time_frame, time_price[j], TimeCurrent()); break; } } break; } } bool prev_touch_up = false; if((low_price[1] < t1_line_value && close_price[1] > open_price[1]) || (low_price[2] < t2_line_value && close_price[2] > open_price[2])) { prev_touch_up = true; // Flag that a recent touch already occurred } if( ((low_price[0] < t_line_value && open_price[0] > t_line_value) || (low_price[1] < t1_line_value && open_price[1] > t1_line_value) || (low_price[2] < t2_line_value && open_price[2] > t2_line_value) || (low_price[3] < t3_line_value && open_price[3] > t3_line_value)) && (close_price[0] > open_price[0]) && close_price[0] > t_line_value && (no_bars_up < 3) && prev_touch_up == false && (currentBarTime != lastTradeBarTime) && (line_exe == reversal || line_exe == reverse_break) ) { take_profit = MathAbs(ask_price + ((ask_price - low_price[0]) * 4)); trade.Buy(lot_size, _Symbol, ask_price, low_price[0],take_profit); lastTradeBarTime = currentBarTime; // Update last trade bar time to avoid duplicate signals } // UPTREND BREAKOUT AMD RETEST bool prev_touch_break_out_up = false; if((high_price[1] > td1_line_value && close_price[1] < open_price[1]) || (high_price[2] > td2_line_value && close_price[2] < open_price[2]) ) { prev_touch_break_out_up = true; } int no_bars_up_break_out = 0; for(int i = 0; i <= 3; i++) { if(high_price[i] > ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) && open_price[i] < ObjectGetValueByTime(chart_id,down_trend,time_price[i],0) ) { for(int j = i; j >= 0; j--) { if(close_price[j] < open_price[j] && close_price[j] < ObjectGetValueByTime(chart_id,down_trend,time_price[j],0)) { no_bars_up_break_out = Bars(_Symbol,time_frame,time_price[j],TimeCurrent()); break; } } break; } } if(((high_price[1] >= t1_line_value && open_price[1] < t1_line_value) || (high_price[2] >= t2_line_value && open_price[2] < t2_line_value) || (high_price[3] >= t3_line_value && open_price[3] < t3_line_value) || (high_price[0] >= t_line_value)) && (close_price[0] < t_line_value && close_price[0] < open_price[0] && open_price[1] < t1_line_value) && (no_bars_up_break_out < 3) && (no_bars_up_break_out == false) && (currentBarTime != lastTradeBarTime) && (line_exe == break_out || line_exe == reverse_break) ) { take_profit = MathAbs(ask_price - ((high_price[0] - ask_price) * 4)); trade.Sell(lot_size,_Symbol,ask_price,high_price[0], take_profit); lastTradeBarTime = currentBarTime; }
Пояснение:
Для определения того, имел ли место какой-либо пробой в недавнем времени, в первом разделе кода используется булев флаг. Когда свеча закрывается как медвежья, советник проверяет предыдущие свечи, чтобы увидеть, коснулся ли их максимум трендовой линии снизу. Чтобы предотвратить множественные сигналы от одного пробоя, флагу присваивается значение true в случае обнаружения такого касания. Это гарантирует, что одно и то же ценовое взаимодействие не приведет к повторному инициированию сделок советником.
Затем советник определяет, сколько баров прошло с момента последнего подтвержденного пробоя. Он сканирует недавние свечи, чтобы выявить те, у которых цена открытия была ниже трендовой линии, а максимум – выше нее. Здесь вложенный цикл ищет последующую свечу, которая закрывается ниже трендовой линии и является медвежьей. Чтобы убедиться, что сделка не исполнится слишком близко к предыдущему пробою, советник подсчитывает бары между такой обнаруженной свечой и текущим баром. Этот счетчик баров используется, чтобы предотвратить чрезмерную торговлю и держать частоту входов под контролем.
Эти несколько проверок объединяются в единый критерий для исполнения сделки на продажу. Чтобы подтвердить ретест, сначала необходимо убедиться, что одна из недавних свечей коснулась трендовой линии или пересекла ее. Затем советник определяет, падает ли текущая свеча ниже трендовой линии и является ли медвежьей, что может указывать на то, что продавцы набирают силу. Сравнивая время текущего бара со временем последней исполненной сделки, он также убеждается, что с момента последнего пробоя не прошло слишком много баров, что ни одно в недавнем времени еще не было пробойных касаний, которые уже вызвали сделку, и что только одна сделка исполняется за каждую свечу. Наконец, советник проверяет, что режим советника допускает исполнение пробойных сделок.
Если все эти условия выполнены, советник рассчитывает тейк-профит, умножая расстояние между текущей ценой Ask и максимумом подтверждающей свечи на определенный коэффициент, обеспечивающий благоприятное соотношение риска к вознаграждению. После этого советник применяет рассчитанный тейк-профит, устанавливает стоп-лосс на максимум пробойной свечи, исполняет ордер на продажу с заданным размером лота и обновляет время бара последней сделки. Исключая повторные и преждевременные сделки, эта логика гарантирует, что советник будет последовательно отслеживать потенциальные пробои с ретестом у восходящей трендовой линии.
Заключение
В продолжение предыдущей статьи о торговле с графическими объектами, в данной статье мы сосредоточились перешли от прямоугольников к трендовым линиям. Вы научились созданию советника, который может выявлять ситуации, когда цена разворачивается от трендовой линии на графике или пробивает ее, и автоматически исполнять сделки на их основе. Сочетая автоматическую торговлю с ручным анализом трендовых линий, этот подход преобразует популярный технический инструмент в рабочие торговые сигналы на языке MQL5.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/19968
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Нейросети в трейдинге: Возмущённые модели пространства состояний для анализа рыночной динамики (Энкодер)
Двунаправленная LSTM и квантовые вычисления для предсказания направления движения
Нейросети в трейдинге: Возмущённые модели пространства состояний для анализа рыночной динамики
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования