English 中文 Español Deutsch 日本語 Português
preview
Теория категорий в MQL5 (Часть 15): Функторы с графами

Теория категорий в MQL5 (Часть 15): Функторы с графами

MetaTrader 5Тестер | 28 ноября 2023, 12:53
648 0
Stephen Njuki
Stephen Njuki

Введение

В предыдущей статье мы рассмотрели, как уже рассмотренные концепции, такие как линейные порядки, можно рассматривать как категории и почему их "морфизмы" действительно представляют собой функторы применительно к другим категориям. Мы рассмотрим примеры из предыдущей статьи, в частности то, как графы могут иметь такое же применение, как линейные порядки, рассмотренные в предыдущей статье. Чтобы использовать графы, мы преобразуем данные календаря MQL5 в виде графа и, следовательно, в виде категории. Это ключевой момент текущей статьи. Таким образом, цель этой статьи, как и предыдущей, — продемонстрировать потенциал функторов в прогнозировании волатильности между двумя категориями. Однако в данном случае наша категория домена представляет собой граф, в то время как кодомен будет отображать значения волатильности S&P 500 (не VIX) в предпорядке временных рядов.


Преобразование входных данных Календаря MQL5 в виде графа

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


Тогда наша гипотеза будет заключаться в том, что показатели розничных продаж (retail sales) являются функцией индекса PMI, который, в свою очередь, является производным от индекса потребительских цен (CPI), а тот зависит от проведения казначейских аукционов (10-year yield auction), результаты которых также основаны на показателях розничных продаж. Итак, это простой цикл, достоверность которого не является предметом статьи, а скорее призвана проиллюстрировать возможный состав графа на основе данных экономического календаря.

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

Поэтому вместо того, чтобы объединять отдельные объекты в этой категории с объектами из категории волатильности S&P, как мы это делали в предыдущей статье о линейных порядках, мы соединим строки пар вершин с категорией S&P. Это означает, что она не может быть изоморфной, поскольку несколько строк привязаны к одному объекту (точке данных) в S&P, учитывая, что S&P основана на времени. Это также означает, что наши объекты домена будут состоять из четырех элементов (последние значения каждого из четырех элементов цикла).


Теория категорий и функторы: краткий обзор

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

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

В предыдущей статье мы протестировали два сценария: в одном мы использовали связь объектов между двумя категориями, а в другом — рассматривали связь морфизма между одними и теми же категориями. Функтор представляет собой логарифм обоих, но для наших целей мы исследовали различия между ними, рассматривая по одному, и сформировали отчеты тестера стратегий для каждого из них, которые подчеркнули относительную важность в прогнозировании волатильности NASDAQ. Учитывая короткое окно тестирования с 1 января по 15марта 2020 года, выводы о том, какой сценарий лучше, сделать не удалось, но разница в результатах свидетельствовала о высокой чувствительности к различиям.


Создание категории волатильности S&P 500

Сбор и обработка данных о волатильности SP500 будут простыми и похожими на то, как мы измеряли волатильность NASDAQ в последней статье. VIX является отдельным индикатором. Таким образом, текущее значение волатильности будет пересчитываться на каждом новом баре согласно приведенному ниже листингу:

      double _float_value=0.0;
      //where R is an instance of MqlRates...
      _float_value=(R.high-R.low)/Point();


Как уже упоминалось, S&P сформирует наш кодомен с объектами, фиксирующими значения волатильности, как один набор объектов, и морфизмами между ними, фиксирующими относительное изменение между показаниями волатильности. Инициализацию этой категории можно выполнить следующим образом:

//+------------------------------------------------------------------+
//|   Get SP500-100 data from symbol (NDX100 for this broker).       | 
//|   Load it into SP500 category.                                   |
//+------------------------------------------------------------------+
void SetSP500(MqlRates &R)
   {
      _hmorph_sp500.Let();
      
      double _float_value=0.0;
      
      _float_value=(R.high-R.low)/Point();
      
      _element_value.Let();_element_value.Cardinality(1);_element_value.Set(0,DoubleToString(_float_value));
      _domain_sp500.Cardinality(1);_domain_sp500.Set(0,_element_value);
      
      //_category_sp500.Domains(_category_sp500.Domains()+1);
      _category_sp500.SetDomain(_category_sp500.Domains(),_domain_sp500);  
   }


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


Функторы от экономического календаря до S&P 500

Мы построим категорию данных экономического календаря, используя листинг ниже:

//+------------------------------------------------------------------+
//|   Get Ocean data from file defined in input.                     | 
//|   Load it into Ocean category.                                   |
//+------------------------------------------------------------------+
void SetEconomic(MqlRates &R)
   {
      datetime _time=R.time;
      
      int _elements=1;
      
      _e_retail.Let();
      SampleEvents(_time,_e_retail,IntToCountry(__country),__currency,TYPE_RETAIL_SALES);//printf(__FUNCSIG__+"...retail. ");
      
      _e_cpi.Let();
      string _cpi_time="";_e_retail.Get(0,_cpi_time);
      SampleEvents(StringToTime(_cpi_time),_e_cpi,IntToCountry(__country),__currency,TYPE_CPI);//printf(__FUNCSIG__+"...cpi. ");
      
      _e_auction.Let();
      string _auction_time="";_e_cpi.Get(0,_auction_time);
      SampleEvents(StringToTime(_auction_time),_e_auction,IntToCountry(__country),__currency,TYPE_AUCTION_10YR);//printf(__FUNCSIG__+"...auction. ");
      
      _e_pmi.Let();
      string _pmi_time="";_e_auction.Get(0,_pmi_time);
      SampleEvents(StringToTime(_pmi_time),_e_pmi,IntToCountry(__country),__currency,TYPE_PMI);//printf(__FUNCSIG__+"...pmi. ");
      
       _domain_economic.Cardinality(__ECON);
       _domain_economic.Set(0,_e_retail);
       _domain_economic.Set(1,_e_cpi);
       _domain_economic.Set(2,_e_auction);
       _domain_economic.Set(3,_e_pmi);
      
       _category_economic.SetDomain(_category_economic.Domains(),_domain_economic);
   }


Каждый объект в этом домене имеет две вершины, которые представляют собой парные календарные значения, из которых по крайней мере одно находится во временном диапазоне значения волатильности в кодомене. Поскольку эти экономические данные публикуются с интервалом примерно в месяц, мы будем тестировать их на месячном графике. Как и в предыдущей статье, наше отображение функтора будет иметь коэффициенты для каждой точки данных в объекте. Разница здесь в том, что мы сталкиваемся с возможностью сопоставления нескольких объектов с одной и той же волатильностью в кодомене. В идеале нам нужно будет получить коэффициент (для линейного отображения) от каждого объекта отдельно и использовать его в прогнозировании. Это означает, что они обязаны предоставлять противоречивые проекции поверх проекций, предоставляемых сопоставлением морфизмов. Вот почему для целей этой статьи мы могли бы взвесить каждый функтор, отображающий календарные данные в категорию S&P, и взять сумму скалярных произведений всех, чтобы сопоставить значение волатильности.

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

//+------------------------------------------------------------------+
//| Get Forecast value, forecast for next change in price bar range. |
//+------------------------------------------------------------------+
double GetObjectsForecast(MqlRates &R)
   {
      double _output=0.0;
      
      //econ init
      SetEconomic(R);
      
      //sp500 init
      SetSP500(R);
      
      matrix _domain;
      vector _codomain,_inputs;
      
      _domain.Init(__ECON+1,__ECON);
      
      for(int r=0;r<__ECON+1;r++)
      {
         CDomain<string> _d;_d.Let();
         _category_economic.GetDomain(_category_economic.Domains()-r-1,_d);
         
         for(int c=0;c<__ECON;c++)
         {
            CElement<string> _e; _d.Get(c,_e);
            
            string _s; _e.Get(1,_s);
            
            _domain[r][c]=StringToDouble(_s);
         }
      }
      
      _codomain.Init(__ECON);
      
      for(int r=0;r<__ECON;r++)
      {
         CDomain<string> _d;_d.Let();
         _category_sp500.GetDomain(_category_sp500.Domains()-r-1,_d);
         
         CElement<string> _e; _d.Get(0,_e);
         
         string _s; _e.Get(0,_s);
            
         _codomain[r]=StringToDouble(_s);
      }
      
      _inputs.Init(__ECON);_inputs.Fill(__constant_morph);
      
      M(_domain,_codomain,_inputs,_output,1);
      
      return(_output);
   }


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

//+--------------------------------------------------------------------+
//|   Get Forecast value, forecast for next change in price bar range. |
//+--------------------------------------------------------------------+
double GetMorphsForecast(MqlRates &R)
   {
      ...
      
      for(int r=0;r<__ECON+1;r++)
      {
         ...
         
         for(int c=0;c<__ECON;c++)
         {
            CElement<string> _e_new; _d_new.Get(c,_e_new);
            
            string _s_new; _e_new.Get(1,_s_new);
            
            CElement<string> _e_old; _d_old.Get(c,_e_old);
            
            string _s_old; _e_old.Get(1,_s_old);
            
            _domain[r][c]=StringToDouble(_s_new)-StringToDouble(_s_old);
         }
      }
      
      _codomain.Init(__ECON);
      
      for(int r=0;r<__ECON;r++)
      {
         ...
         
         CElement<string> _e_new; _d_new.Get(0,_e_new);
         
         string _s_new; _e_new.Get(0,_s_new);
         
         CElement<string> _e_old; _d_old.Get(0,_e_old);
         
         string _s_old; _e_old.Get(0,_s_old);
         
         _codomain[r]=StringToDouble(_s_new)-StringToDouble(_s_old);
      }
      
      _inputs.Init(__ECON);_inputs.Fill(__constant_morph);
      
      M(_domain,_codomain,_inputs,_output,1);
      
      return(_output);
   }


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


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


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

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

2023.07.30 13:45:47.035 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.01.01 00:00, with actual being: 54260.00000000
2023.07.30 13:45:47.134 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.02.01 00:00, with actual being: 95438.00000000
2023.07.30 13:45:47.265 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.03.01 00:00, with actual being: 53588.00000000
2023.07.30 13:45:47.392 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.04.01 00:00, with actual being: 30352.00000000
2023.07.30 13:45:47.512 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 0.00000000, on: 2020.05.01 00:00, with actual being: 29694.00000000
2023.07.30 13:45:47.644 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -716790.11376869, on: 2020.06.01 00:00, with actual being: 21905.00000000
2023.07.30 13:45:47.740 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -12424.22112077, on: 2020.07.01 00:00, with actual being: 26509.00000000
2023.07.30 13:45:47.852 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 53612.17123096, on: 2020.08.01 00:00, with actual being: 37890.00000000




...

2023.07.30 13:45:50.294 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -27774.72154618, on: 2022.09.01 00:00, with actual being: 42426.00000000
2023.07.30 13:45:50.377 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 46751.59791572, on: 2022.10.01 00:00, with actual being: 39338.00000000
2023.07.30 13:45:50.487 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -19820.29385469, on: 2022.11.01 00:00, with actual being: 37305.00000000
2023.07.30 13:45:50.593 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -5370.60103622, on: 2022.12.01 00:00, with actual being: 30192.00000000
2023.07.30 13:45:50.700 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -4662833.98425755, on: 2023.01.01 00:00, with actual being: 25359.00000000
2023.07.30 13:45:50.795 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: 33455.47933459, on: 2023.02.01 00:00, with actual being: 30681.00000000
2023.07.30 13:45:50.905 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -40357.22273603, on: 2023.03.01 00:00, with actual being: 12502.00000000
2023.07.30 13:45:51.001 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -37676.03496283, on: 2023.04.01 00:00, with actual being: 18835.00000000
2023.07.30 13:45:51.094 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -54634.02723538, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 13:45:51.178 ct_15_w (SPX500,MN1)    void OnStart() Objects forecast is: -35897.40757724, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 13:45:51.178 ct_15_w (SPX500,MN1)    void OnStart() corr is: 0.36053106 with morph constant as: 50000.00000000


Сопоставление морфизмов выдает следующие результаты:

2023.07.30 13:47:38.737 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.01.01 00:00, with actual being: 54260.00000000
2023.07.30 13:47:38.797 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.02.01 00:00, with actual being: 95438.00000000
2023.07.30 13:47:38.852 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.03.01 00:00, with actual being: 53588.00000000
2023.07.30 13:47:38.906 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.04.01 00:00, with actual being: 30352.00000000
2023.07.30 13:47:39.010 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 0.00000000, on: 2020.05.01 00:00, with actual being: 29694.00000000
2023.07.30 13:47:39.087 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -2482719.31391738, on: 2020.06.01 00:00, with actual being: 21905.00000000




...

2023.07.30 13:47:41.541 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -86724.54189079, on: 2022.11.01 00:00, with actual being: 37305.00000000
2023.07.30 13:47:41.661 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -126817.99564744, on: 2022.12.01 00:00, with actual being: 30192.00000000
2023.07.30 13:47:41.793 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -198737.93199622, on: 2023.01.01 00:00, with actual being: 25359.00000000
2023.07.30 13:47:41.917 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -280104.88246660, on: 2023.02.01 00:00, with actual being: 30681.00000000
2023.07.30 13:47:42.037 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 24129.34336223, on: 2023.03.01 00:00, with actual being: 12502.00000000
2023.07.30 13:47:42.157 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 4293.73674465, on: 2023.04.01 00:00, with actual being: 18835.00000000
2023.07.30 13:47:42.280 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: 763492.31964126, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 13:47:42.401 ct_15_w (SPX500,MN1)    void OnStart() Morphs forecast is: -30298.30836734, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 13:47:42.401 ct_15_w (SPX500,MN1)    void OnStart() corr is: 0.03400012 with morph constant as: 50000.00000000


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

//+------------------------------------------------------------------+
//| Normalizes negative projections to positive number.              |
//+------------------------------------------------------------------+
double NormalizeForecast(double NegativeValue,double CurrentActual,double PreviousActual,double PreviousForecast)
   {
      return(CurrentActual+(((CurrentActual-NegativeValue)/CurrentActual)*fabs(PreviousActual-PreviousForecast)));
   }


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

2023.07.30 14:43:42.224 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 15650.00000000, on: 2020.01.01 00:00, with actual being: 54260.00000000

...

2023.07.30 14:43:45.895 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 15718.63125861, on: 2023.03.01 00:00, with actual being: 12502.00000000
2023.07.30 14:43:45.957 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 12187.53007421, on: 2023.04.01 00:00, with actual being: 18835.00000000
2023.07.30 14:43:46.026 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 19185.80075759, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 14:43:46.129 ct_15_w_n (SPX500,MN1)  void OnStart() Objects forecast is: 11544.54076238, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 14:43:46.129 ct_15_w_n (SPX500,MN1)  void OnStart() correlation is: 0.46195608 with morph constant as: 0.00000000


Затем мы запускаем наш скрипт, создавая проекции на основе функтора морфизм-морфизм, снова с той же константой уравнения, равной нулю.

2023.07.30 14:45:54.257 ct_15_w_n (SPX500,MN1)  void OnStart() Morphs forecast is: 54260.00000000, on: 2020.02.01 00:00, with actual being: 95438.00000000

...

2023.07.30 14:45:57.449 ct_15_w_n (SPX500,MN1)  void OnStart() Morphs forecast is: 257937.92970615, on: 2023.05.01 00:00, with actual being: 28877.00000000
2023.07.30 14:45:57.527 ct_15_w_n (SPX500,MN1)  void OnStart() Morphs forecast is: 679078.55629755, on: 2023.06.01 00:00, with actual being: 23306.00000000
2023.07.30 14:45:57.527 ct_15_w_n (SPX500,MN1)  void OnStart() correlation is: -0.03589660 with morph constant as: 0.00000000


Мы получаем немного более высокую корреляцию — 0,46 по сравнению с числом 0,3, которое мы получили без нормализации. Это может указывать на некоторые преимущества от нормализации, но в нашем случае входная константа была изменена с 50 000, и, как уже упоминалось, прогнозы и, следовательно, корреляция очень чувствительны к ней. Поскольку у нас есть только один входной сигнал, запустим тестер стратегий для оптимизации его значения и получения более значимых результатов.


Последствия для трейдеров

На мой взгляд, недооцененная ценность теории категорий для финансового анализа заключается в трансферном обучении (transfer learning). Каковы же его преимущества? В результате наших тестов, приведенных выше, мы получили коэффициенты между сопоставлением функторов объекта и сопоставлением морфизмов. Процесс получения этих коэффициентов обязательно потребует больших вычислительных ресурсов, особенно если оптимизация производится, как и следовало ожидать, на длительных исторических периодах в тестере стратегий MQL5.

И все же, поскольку коэффициенты функторов являются частью установленной гипотезы, которая была выдвинута выше в виде цикла, можно утверждать, что эти коэффициенты, которые работают особым образом для значений USD из экономического календаря, могут быть столь же эффективными, скажем, на значениях экономического календаря EUR на волатильности EURO-STOXX или на значениях GBP на волатильности FTSE. Мы получаем набор возможных комбинаций. И здесь наши функторы становятся неоценимыми инструментами в использовании коэффициентов, полученных в результате одной длительной оптимизации с интенсивными вычислениями, и применении их к любой из этих комбинаций, которая (на основе нашей гипотезы) может дать результат лучше среднего.

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


Давайте проведем несколько тестов с альтернативными валютами и соответствующими им фондовыми индексами. Если мы начнем со значений экономического календаря EUR, полученных из Германии, в категории, сопряженной функтором с категорией волатильности DAX30, то с указанными выше настройками мы получим следующий отчет тестера:

2023.07.30 15:12:25.655	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 75550.00000000, on: 2020.01.01 00:00, with actual being: 210640.00000000
2023.07.30 15:12:25.727	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 210640.00000000, on: 2020.02.01 00:00, with actual being: 431320.00000000

...

2023.07.30 15:12:28.445	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 144734.23693128, on: 2022.09.01 00:00, with actual being: 154697.00000000
2023.07.30 15:12:28.539	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 171908.69769099, on: 2022.10.01 00:00, with actual being: 156643.00000000
2023.07.30 15:12:28.648	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 298789.42486333, on: 2022.11.01 00:00, with actual being: 99044.00000000
2023.07.30 15:12:28.753	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 178962.89317906, on: 2022.12.01 00:00, with actual being: 137604.00000000
2023.07.30 15:12:28.901	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 440957.33259197, on: 2023.01.01 00:00, with actual being: 55544.00000000
2023.07.30 15:12:29.032	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 143198.91357580, on: 2023.02.01 00:00, with actual being: 124659.00000000
2023.07.30 15:12:29.151	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 24327.24201304, on: 2023.03.01 00:00, with actual being: 48737.00000000
2023.07.30 15:12:29.267	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 167059.32862279, on: 2023.04.01 00:00, with actual being: 69888.00000000
2023.07.30 15:12:29.357	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 67301.73632062, on: 2023.05.01 00:00, with actual being: 74073.00000000
2023.07.30 15:12:29.470	ct_15_w_n (GER30,MN1)	void OnStart() Objects forecast is: 87406.10063493, on: 2023.06.01 00:00, with actual being: 104992.00000000
2023.07.30 15:12:29.470	ct_15_w_n (GER30,MN1)	void OnStart() correlation is: 0.02260757 with morph constant as: 0.00000000


Для GBP и FTSE-100 мы получаем следующее:

2023.07.30 15:12:45.341	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 45860.00000000, on: 2020.01.01 00:00, with actual being: 109780.00000000
2023.07.30 15:12:45.381	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 109780.00000000, on: 2020.02.01 00:00, with actual being: 210420.00000000
2023.07.30 15:12:45.420	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 210420.00000000, on: 2020.03.01 00:00, with actual being: 87250.00000000
2023.07.30 15:12:45.466	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 87250.00000000, on: 2020.04.01 00:00, with actual being: 58380.00000000
2023.07.30 15:12:45.508	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 1581489.63705309, on: 2020.05.01 00:00, with actual being: 58370.00000000

...

2023.07.30 15:12:46.685	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 153576.16806574, on: 2023.01.01 00:00, with actual being: 30453.00000000
2023.07.30 15:12:46.710	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 222058.94934174, on: 2023.02.01 00:00, with actual being: 77051.00000000
2023.07.30 15:12:46.739	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 50993.02046828, on: 2023.03.01 00:00, with actual being: 30780.00000000
2023.07.30 15:12:46.784	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 66795.26430874, on: 2023.04.01 00:00, with actual being: 45453.00000000
2023.07.30 15:12:46.832	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 75492.86146563, on: 2023.05.01 00:00, with actual being: 28845.00000000
2023.07.30 15:12:46.876	ct_15_w_n (UK100,MN1)	void OnStart() Objects forecast is: 92298.50964858, on: 2023.06.01 00:00, with actual being: 49472.00000000
2023.07.30 15:12:46.876	ct_15_w_n (UK100,MN1)	void OnStart() correlation is: 0.14415363 with morph constant as: 0.00000000


Из наших первоначальных записей ясно, что, хотя мы и можем делать прогнозы, мы не можем их достоверно проверить из-за ограниченного использования календарных данных в тестере стратегий. Очевидно, что наша гипотеза не подтвердилась, и корреляция 0,46, полученная для доллара США и SP500, вряд ли была окончательной. 

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

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

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

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

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

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


Заключение

Основные моменты, затронутые в статье, - составление данных экономического календаря в виде графика, просмотр этого графика как категории и, как и в нашей предыдущей статье, использование отношения функтора, которое отстает от волатильности индекса S&P 500, для составления прогнозов волатильности индекса S&P 500. Как и в предыдущих частях серии, мы используем эти прогнозы для перемещения трейлинг-стопов открытых позиций. Помимо настройки стоп-лосса для открытых позиций, мы могли бы использовать соотношение функтора, чтобы установить размер позиции новых ордеров или даже определить сигнал входа для любой торгуемой ценной бумаги. В этой серии статей мы воздерживаемся от этих двух последних примеров, поскольку речь идет о сборке советника с помощью мастера IDE. Пользователь затем сам может внести необходимые изменения в соответствии со своей собственной стратегией. Мы также рассмотрели определение морфинга, а теперь и функторных отношений. Мы использовали грубые инкрементальные значения, которые могли иметь линейную или квадратичную связь от домена к кодомену, но для определения этого сопоставления также можно использовать искусственные нейронные сети. Возможно, эта тема будет рассмотрена в следующих статьях.


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

Прикрепленные файлы |
ct_14_1s.mqh (73.52 KB)
ct_15_w.mq5 (17.23 KB)
ct_15_w_n.mq5 (18.41 KB)
Python, ONNX и MetaTrader 5: Создаем модель RandomForest с предварительной обработкой данных RobustScaler и PolynomialFeatures Python, ONNX и MetaTrader 5: Создаем модель RandomForest с предварительной обработкой данных RobustScaler и PolynomialFeatures
В этой статье мы создадим модель случайного леса на языке Python, обучим модель и сохраним ее в виде конвейера ONNX с препроцессингом данных. Модель мы далее используем в терминале MetaTrader 5.
Популяционные алгоритмы оптимизации: Дифференциальная эволюция (Differential Evolution, DE) Популяционные алгоритмы оптимизации: Дифференциальная эволюция (Differential Evolution, DE)
В этой статье поговорим об алгоритме, который демонстрирует самые противоречивые результаты из всех рассмотренных ранее, алгоритм дифференциальной эволюции (DE).
Изучение MQL5 от новичка до профи (Часть I): Начинаем программировать Изучение MQL5 от новичка до профи (Часть I): Начинаем программировать
Эта статья является вводной для целого цикла статей о программировании. Здесь предполагается, что читатель вообще не сталкивался с программированием раньше. Поэтому начинаю я с самых основ. Уровень знания программирования: абсолютный новичок.
Нейросети — это просто (Часть 65): Дистанционно-взвешенное обучение с учителем (DWSL) Нейросети — это просто (Часть 65): Дистанционно-взвешенное обучение с учителем (DWSL)
В данной статье я предлагаю Вам познакомиться с интересным алгоритмом, который построен на стыке методов обучения с учителем и подкреплением.