English 中文 Español Deutsch 日本語
preview
Переосмысливаем классические стратегии в MQL5 (Часть II): FTSE100 и Гилты Великобритании

Переосмысливаем классические стратегии в MQL5 (Часть II): FTSE100 и Гилты Великобритании

MetaTrader 5Примеры | 31 марта 2025, 07:53
378 2
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

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


Обзор торговой стратегии

Financial Times Stock Exchange 100 (FTSE 100) - это всемирно признанный индекс, отслеживающий показатели 100 крупнейших компаний, котирующихся на Лондонской фондовой бирже (LSE). Индекс создан в 1984 году со значением 1000 пунктов и в настоящее время торгуется на отметке около 8000 пунктов. Компании, входящие в индекс, оцениваются пропорционально их рыночной капитализации, что означает, что крупные компании оказывают большее влияние на рынок, чем компании меньшего размера.

Все правительства развитых стран выпускают обязательства, номинированные в их национальной валюте, и правительство Великобритании не является исключением. Гилт (Gilt) - это государственный долговой инструмент Великобритании, который также котируется на Лондонской фондовой бирже. Гилты - это ценные бумаги с фиксированным доходом, которые выпускаются в 2-х различных вариантах. Первый тип - это обыкновенный гилт и он составляет большую часть продаж гилта. По этому обыкновенному гилту выплачивается фиксированный купон на предъявителя гилта до наступления срока погашения, по истечении которого инвестору возвращается окончательный купон и основная сумма долга.

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


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

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

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



Обзор методологии

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

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

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


Реализация средствами MQL5

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

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

//+------------------------------------------------------------------+
//|                                                  UK100 Gilts.mq5 |
//|                                        Gamuchirai Zororo Ndawana |
//|                          https://www.mql5.com/en/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com/en/gamuchiraindawa"
#property version   "1.00"
#property script_show_inputs

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
input int fetch = 20;                  //How much data should we fetch?
input int look_ahead = 20;             //How far into the future should we forecast?

Теперь мы можем приступить к определению сути нашего скрипта. Сначала определим переменные, которые нам будут нужны на протяжении всего нашего скрипта.

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Global variables we will need inside our expert advisor
   matrix coefficients = matrix::Zeros(1,9);
   vector mean_values = vector::Zeros(8);
   vector std_values = vector::Zeros(8);
   vector intercept = vector::Ones(fetch);
   matrix input_matrix = matrix::Zeros(9,fetch);
   matrix gilts_data,uk100_data,target;

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

//--- First we will fetch the market data
   gilts_data.CopyRates("UKGB_Z4",PERIOD_CURRENT,COPY_RATES_OHLC,1+look_ahead,fetch);
   uk100_data.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_OHLC,1+look_ahead,fetch);
   target.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_CLOSE,1,fetch);

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

//--- Fill in the input matrix
   input_matrix.Row(intercept,0);
   input_matrix.Row(gilts_data.Row(0),1);
   input_matrix.Row(gilts_data.Row(1),2);
   input_matrix.Row(gilts_data.Row(2),3);
   input_matrix.Row(gilts_data.Row(3),4);
   input_matrix.Row(uk100_data.Row(0),5);
   input_matrix.Row(uk100_data.Row(1),6);
   input_matrix.Row(uk100_data.Row(2),7);
   input_matrix.Row(uk100_data.Row(3),8);

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

//--- Display the data fetched
   Print("Input matrix: ");
   Print("Rows: ",input_matrix.Rows()," Columns: ",input_matrix.Cols());
   Print(input_matrix);

   Print("Target: ");
   Print("Rows: ",target.Rows()," Columns: ",target.Cols());
   Print(target);

   Print("UK100: ");
   Print("Rows: ",uk100_data.Rows()," Columns: ",uk100_data.Cols());
   Print(uk100_data);

   Print("GILTS: ");
   Print("Rows: ",gilts_data.Rows()," Columns: ",gilts_data.Cols());
   Print(gilts_data);

Чтобы масштабировать и нормализовать наши входные данные, нужно вычислить среднее значение и значение стандартного отклонения для каждого столбца, с которым мы имеем дело. Когда я только начинал изучать машинное обучение, я не был уверен, когда возникает необходимость в масштабировании и стандартизации данных. Однако со временем я усвоил эмпирическое правило, что масштабирование необходимо, когда ваши исходные данные находятся в разных масштабах, так, например, наши рыночные данные по гилтам находятся в диапазоне 100, а наши рыночные данные по FTSE100 - в диапазоне 8000, поэтому масштабирование здесь необходимо. Обратите внимание, что в масштабировании цели необходимость отсутствует.

//--- Calculate the scaling values
   mean_values = input_matrix.Mean(1);
   std_values = input_matrix.Std(1);
   Print("Mean values: ");
   Print(mean_values);

   Print("Std values: ");
   Print(std_values);

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

//--- Normalizing and scaling our input data
   for(int i = 0; i < 8; i++)
     {
      //--- Extract the vector
      vector temp = input_matrix.Row(i + 1);
      //--- Scale the data
      temp = ((temp - mean_values[i+1]) / std_values[i+1]);
      //--- Write the data back
      input_matrix.Row(temp,i+1);
     }

//--- Finished normalizing the data
   Print("Finished normalizing the data.");
   Print(input_matrix);

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

//--- Now we can calculate our coefficient values
   coefficients = target.MatMul(input_matrix.PInv());

   Print("Coefficient values");
   Print(coefficients);

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

//--- Now we can obtain a forecast from our model
   gilts_data.CopyRates("UKGB_Z4",PERIOD_CURRENT,COPY_RATES_OHLC,0,1);
   uk100_data.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_OHLC,0,1);

//--- Scale our inputs
   gilts_data[0,0] = ((gilts_data[0,0] - mean_values[1]) / std_values[1]);
   gilts_data[1,0] = ((gilts_data[1,0] - mean_values[2]) / std_values[2]);
   gilts_data[2,0] = ((gilts_data[2,0] - mean_values[3]) / std_values[3]);
   gilts_data[3,0] = ((gilts_data[3,0] - mean_values[4]) / std_values[4]);
   uk100_data[0,0] = ((uk100_data[0,0] - mean_values[5]) / std_values[5]);
   uk100_data[1,0] = ((uk100_data[1,0] - mean_values[6]) / std_values[6]);
   uk100_data[2,0] = ((uk100_data[2,0] - mean_values[7]) / std_values[7]);
   uk100_data[3,0] = ((uk100_data[3,0] - mean_values[8]) / std_values[8]);

   Print("Normalized inputs: ");
   Print(gilts_data);
   Print(uk100_data);

   double forecast = (
                        (1 * coefficients[0,0]) +
                        (gilts_data[0,0] * coefficients[0,1]) +
                        (gilts_data[1,0] * coefficients[0,2]) +
                        (gilts_data[2,0] * coefficients[0,3]) +
                        (gilts_data[3,0] * coefficients[0,4]) +
                        (uk100_data[0,0] * coefficients[0,5]) +
                        (gilts_data[1,0] * coefficients[0,6]) +
                        (gilts_data[2,0] * coefficients[0,7]) +
                        (gilts_data[3,0] * coefficients[0,8])
                     );

//--- Give our predictions
   Comment("Model forecast: ",forecast);

Our script

Рис 1: Наш скрипт

Our script inputs.

Рис 2: Входные параметры нашего скрипта

Our model forecast

Рис 3: Прогноз нашей модели


Создание нашего эксперта на MQL5

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

//+------------------------------------------------------------------+
//|                                                  UK100 Gilts.mq5 |
//|                                        Gamuchirai Zororo Ndawana |
//|                          https://www.mql5.com/en/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Zororo Ndawana"
#property link      "https://www.mql5.com/en/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//|Libraries we need                                                 |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>             //Trade class
CTrade Trade;                          //Initialize the class

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

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
input int fetch = 20;                  //How much data should we fetch?
input int look_ahead = 20;             //How far into the future should we forecast?

Нам также нужны глобальные переменные, которые будут использоваться на протяжении всей программы.

//+------------------------------------------------------------------+
//| Global vairables                                                 |
//+------------------------------------------------------------------+
matrix coefficients = matrix::Zeros(1,9);
vector mean_values = vector::Zeros(8);
vector std_values = vector::Zeros(8);
vector intercept = vector::Ones(fetch);
matrix input_matrix = matrix::Zeros(9,fetch);
matrix gilts_data,uk100_data,target;
double willr_buffer[],rsi_buffer[];
int willr_handler,rsi_handler;
double forecast,bid,ask;
int model_forecast = 0;
int state = 0;

Давайте определим функцию, ответственную за выборку наших обучающих данных и получение значений масштабирования, необходимых нам для стандартизации и масштабирования наших данных. Обратите внимание, что мы используем матрицы вместо массивов, поскольку намерены воспользоваться преимуществами специализированных матричных и векторных функций, включенных в MQL5 API.

//+------------------------------------------------------------------+
//| Let us fetch our training data                                   |
//+------------------------------------------------------------------+
void fetch_training_data(void)
  {
//--- First we will fetch the market data
   gilts_data.CopyRates("UKGB_Z4",PERIOD_CURRENT,COPY_RATES_OHLC,1+look_ahead,fetch);
   uk100_data.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_OHLC,1+look_ahead,fetch);
   target.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_CLOSE,1,fetch);

//--- Fill in the input matrix
   input_matrix.Row(intercept,0);
   input_matrix.Row(gilts_data.Row(0),1);
   input_matrix.Row(gilts_data.Row(1),2);
   input_matrix.Row(gilts_data.Row(2),3);
   input_matrix.Row(gilts_data.Row(3),4);
   input_matrix.Row(uk100_data.Row(0),5);
   input_matrix.Row(uk100_data.Row(1),6);
   input_matrix.Row(uk100_data.Row(2),7);
   input_matrix.Row(uk100_data.Row(3),8);

//--- Display the data fetched
   Print("Input matrix: ");
   Print("Rows: ",input_matrix.Rows()," Columns: ",input_matrix.Cols());
   Print(input_matrix);

   Print("Target: ");
   Print("Rows: ",target.Rows()," Columns: ",target.Cols());
   Print(target);

   Print("UK100: ");
   Print("Rows: ",uk100_data.Rows()," Columns: ",uk100_data.Cols());
   Print(uk100_data);

   Print("GILTS: ");
   Print("Rows: ",gilts_data.Rows()," Columns: ",gilts_data.Cols());
   Print(gilts_data);

//--- Calculate the scaling values
   mean_values = input_matrix.Mean(1);
   std_values = input_matrix.Std(1);

   Print("Mean values: ");
   Print(mean_values);

   Print("Std values: ");
   Print(std_values);
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//| Let us scale and standardize the training data                   |
//+------------------------------------------------------------------+
void scale_training_data(void)
  {
//--- Normalizing and scaling our input data
   for(int i = 0; i < 8; i++)
     {
      //--- Extract the vector
      vector temp = input_matrix.Row(i + 1);
      //--- Scale the data
      temp = ((temp - mean_values[i+1]) / std_values[i+1]);
      //--- Write the data back
      input_matrix.Row(temp,i+1);
     }

//--- Finished normalizing the data
   Print("Finished normalizing the data.");
   Print(input_matrix);
  }

После того, как наши обучающие данные будут масштабированы и стандартизированы, мы будем готовы к расчету параметров нашей модели.

//+------------------------------------------------------------------+
//| Calculate coefficient values                                     |
//+------------------------------------------------------------------+
void calculate_coefficient_values(void)
  {
//--- Now we can calculate our coefficient values
   coefficients = target.MatMul(input_matrix.PInv());

   Print("Coefficient values");
   Print(coefficients);
  }

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

//+------------------------------------------------------------------+
//| Fetch a forecast from our model                                  |
//+------------------------------------------------------------------+
void fetch_forecast(void)
  {
//--- Now we can obtain a forecast from our model
   gilts_data.CopyRates("UKGB_Z4",PERIOD_CURRENT,COPY_RATES_OHLC,0,1);
   uk100_data.CopyRates("UK100",PERIOD_CURRENT,COPY_RATES_OHLC,0,1);

//--- Scale our inputs
   gilts_data[0,0] = ((gilts_data[0,0] - mean_values[1]) / std_values[1]);
   gilts_data[1,0] = ((gilts_data[1,0] - mean_values[2]) / std_values[2]);
   gilts_data[2,0] = ((gilts_data[2,0] - mean_values[3]) / std_values[3]);
   gilts_data[3,0] = ((gilts_data[3,0] - mean_values[4]) / std_values[4]);
   uk100_data[0,0] = ((uk100_data[0,0] - mean_values[5]) / std_values[5]);
   uk100_data[1,0] = ((uk100_data[1,0] - mean_values[6]) / std_values[6]);
   uk100_data[2,0] = ((uk100_data[2,0] - mean_values[7]) / std_values[7]);
   uk100_data[3,0] = ((uk100_data[3,0] - mean_values[8]) / std_values[8]);

   Print("Normalized inputs: ");
   Print(gilts_data);
   Print(uk100_data);

//--- Calculate the model's prediction
   forecast = (
                 (1 * coefficients[0,0]) +
                 (gilts_data[0,0] * coefficients[0,1]) +
                 (gilts_data[1,0] * coefficients[0,2]) +
                 (gilts_data[2,0] * coefficients[0,3]) +
                 (gilts_data[3,0] * coefficients[0,4]) +
                 (uk100_data[0,0] * coefficients[0,5]) +
                 (gilts_data[1,0] * coefficients[0,6]) +
                 (gilts_data[2,0] * coefficients[0,7]) +
                 (gilts_data[3,0] * coefficients[0,8])
              );

//--- Store the model's prediction
   if(forecast < iClose("UK100",PERIOD_CURRENT,0))
     {
      model_forecast = -1;
     }

   if(forecast > iClose("UK100",PERIOD_CURRENT,0))
     {
      model_forecast = 1;
     }

//--- Give the user feedback
   Comment("Model forecast: ",forecast);
  }

Наконец, нам также нужна функция для получения текущих рыночных данных и данных технических индикаторов.

//+------------------------------------------------------------------+
//| This function will fetch current market data                     |
//+------------------------------------------------------------------+
void update_market_data(void)
  {
//--- Market prices
   bid = SymbolInfoDouble("UK100",SYMBOL_BID);
   ask = SymbolInfoDouble("UK100",SYMBOL_ASK);

//--- Technical indicators
   CopyBuffer(rsi_handler,0,0,1,rsi_buffer);
   CopyBuffer(willr_handler,0,0,1,willr_buffer);
  }

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

//+------------------------------------------------------------------+
//| This function will check if we have oppurtunities to buy         |
//+------------------------------------------------------------------+
void check_bullish_sentiment(void)
  {
   if((willr_buffer[0] > -20) && (rsi_buffer[0] > 70))
     {
      Trade.Buy(0.2,"UK100",ask,ask-5,ask+5,"UK100 Gilts AI");
      state = 1;
     }
  }

//+------------------------------------------------------------------+
//| This function will check if we have oppurtunities to sell        |
//+------------------------------------------------------------------+
void check_bearish_sentiment(void)
  {
   if((willr_buffer[0] < -80) && (rsi_buffer[0] <370))
     {
      Trade.Sell(0.2,"UK100",ask,ask-5,ask+5,"UK100 Gilts AI");
      state = -1;
     }
  }

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

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Fetch the training data
   fetch_training_data();

//--- Scale the training data
   scale_training_data();

//--- Calculate the coefficients
   calculate_coefficient_values();

//--- Setup the indicators
   rsi_handler = iRSI("UK100",PERIOD_CURRENT,20,PRICE_CLOSE);
   willr_handler = iWPR("UK100",PERIOD_CURRENT,30);

//--- Validate the technical indicators
   if((rsi_handler == INVALID_HANDLE) || (willr_handler == INVALID_HANDLE))
     {
      Comment("Failed to load indicators. ",GetLastError());
      return(INIT_FAILED);
     }

//--- Everything went well
   return(INIT_SUCCEEDED);
  }

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

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Free up the resoruces we don't need
   IndicatorRelease(willr_handler);
   IndicatorRelease(rsi_handler);
   ExpertRemove();
  }

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

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Fetch updated market data
   update_market_data();

//--- Fetch a forecast from our model
   fetch_forecast();

//--- Check for a position we can open
   if(PositionsTotal() == 0)
     {
      if(model_forecast == 1)
        {
         check_bullish_sentiment();
        }

      else
         if(model_forecast == -1)
           {
            check_bearish_sentiment();
           }
     }

//--- Check for a reversal
   else
      if(PositionsTotal() > 0)
        {
         if(model_forecast != state)
           {
            Alert("Reversal detected by our AI system! Closing all positions now.");
            Trade.PositionClose("UK100");
           }
        }
  }
//+------------------------------------------------------------------+

Наша система в действии

Рис 4: Наша система ИИ в действии


Заключение

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

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15771

Прикрепленные файлы |
UK100_Gilts.mq5 (10.13 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
Omnitek
Omnitek | 6 сент. 2024 в 23:17
Хорошее объяснение каждой секции кода.
Я думаю, что в вашем расчете прогноза есть ошибка, когда данные guilt_data добавляются в 7-е, 8-е и 9-е данные вместо данных uk100.
Если это было сделано намеренно, то чем вы это обосновываете?

В любом случае, хорошая статья. Будьте здоровы.
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana | 6 сент. 2024 в 23:47
Omnitek #:
Хорошее объяснение каждой секции кода.
Я думаю, что в вашем расчете прогноза есть ошибка, когда данные guilt_data повторно добавляются в 7-е, 8-е и 9-е данные вместо данных uk100.
Если это было сделано намеренно, то чем вы это обосновываете?

В любом случае, хорошая статья. Будьте здоровы.
Здравствуйте, спасибо за ваш отзыв.

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

После пересмотра я теперь вижу ошибку, я явно вызывал данные guilts дважды вместо того, чтобы получить данные UK100, к счастью, это человеческий фактор, а не ошибка в языке MQL5.
MQL5-советник, интегрированный в Telegram (Часть 5): Отправка команд из Telegram в MQL5 и получение ответов в реальном времени MQL5-советник, интегрированный в Telegram (Часть 5): Отправка команд из Telegram в MQL5 и получение ответов в реальном времени
В этой статье мы создадим несколько классов для облегчения взаимодействия в реальном времени между MQL5 и Telegram. Мы займемся извлечением команд из Telegram, их декодированием и интерпретацией, а также отправкой соответствующих ответов. Под конец мы протестируем эти взаимодействия и убедимся в их правильной работе в торговой среде.
Треугольные и пилообразные волны: инструменты для трейдера Треугольные и пилообразные волны: инструменты для трейдера
Одним из методов технического анализа является волновой анализ. В этой статье мы рассмотрим волны несколько необычного вида — треугольные и пилообразные. На основе этих волн можно построить несколько технических индикаторов, с помощью которых можно анализировать движение цены на рынке.
Нейросети в трейдинге: Выявление аномалий в частотной области (CATCH) Нейросети в трейдинге: Выявление аномалий в частотной области (CATCH)
Фреймворк CATCH сочетает преобразование Фурье и частотный патчинг для точного выявления рыночных аномалий, недоступных традиционным методам. В данной работе мы рассмотрим, как этот подход раскрывает скрытые закономерности в финансовых данных.
Самооптимизирующийся советник на языках MQL5 и Python (Часть III): Реализация алгоритма Boom 1000 Самооптимизирующийся советник на языках MQL5 и Python (Часть III): Реализация алгоритма Boom 1000
В этой серии статей мы обсуждаем создание советников, способных автономно подстраиваться под динамичные рыночные условия. В сегодняшней статье мы попытаемся настроить глубокую нейронную сеть для синтетических рынков Deriv.