
Переосмысливаем классические стратегии в MQL5 (Часть II): FTSE100 и Гилты Великобритании
У современного инвестора есть потенциально бесконечное количество способов интегрировать искусственный интеллект в свои торговые стратегии. Крайне маловероятно, что у какого-либо индивидуального инвестора будет достаточно времени, чтобы тщательно проанализировать каждую стратегию, прежде чем решить, какой из них доверить свой капитал. В настоящей серии статей мы исследуем широкий спектр возможных применений искусственного интеллекта в торговой среде. Наша цель - помочь вам определить стратегию, которая подходит для вашего конкретного профиля инвестора.
Обзор торговой стратегии
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);
Рис 1: Наш скрипт
Рис 2: Входные параметры нашего скрипта
Рис 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





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Ознакомьтесь с новой статьей: Переосмысление классических стратегий на MQL5 (часть II): FTSE100 и UK Gilts.
Автор: Гамучирай Зороро Ндавана
Хорошее объяснение каждой секции кода.