English 中文 Español Deutsch 日本語 Português
Портфельная торговля в MetaTrader 4

Портфельная торговля в MetaTrader 4

MetaTrader 4Примеры | 8 сентября 2016, 12:55
29 384 24
transcendreamer
transcendreamer

Magnus ab integro saeclorum nascitur ordo
Publius Vergilius Maro, Eclogues

Введение

Портфельный принцип в инвестициях известен с очень ранних времён. Распределяя средства по нескольким направлениям, владелец тем самым создает портфель, уменьшает общий риск потерь за счёт диверсификации и делает рост доходов более плавным. Значительное развитие портфельная теория получила после того, как в 1950 году Гарри Марковиц сформулировал первую математическую модель портфеля. Позже, в 1980-ых годах, группа исследователей из Morgan Stanley создала первую стратегию спред-трейдинга, что открыло новое направление: рыночно-нейтральные стратегии. Современная портфельная теория многообразна и сложна, и количество вариантов портфельных стратегий с трудом поддаётся описанию. В этой статье будет рассмотрен только небольшой спектр спекулятивных стратегий и пример реализации на платформе MetaTrader 4.

Некоторые определения, действующие для этой статьи:

  • Портфель (корзина, синтетический инструмент) — набор позиций по нескольким торговым инструментам, с рассчитанными оптимальными объёмами. Позиции удерживаются в течение некоторого времени, отслеживаются как единое целое и закрываются с общим финансовым результатом.
  • Корректировка портфеля (корзины, синтетического инструмента) — изменение состава инструментов и/или их объёмов в портфеле с целью минимизации потерь либо фиксации промежуточного результата.
  • Синтетический объём — количество синтетических позиций (сколько раз портфель был куплен или продан).
  • Виртуальная прибыль/убыток — финансовый результат, который мог быть получен при удержании позиций в некотором интервале времени.

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


Принципы

Построение портфеля включает два этапа: выбор инструментов и расчёт лотов и направлений для выбранных инструментов. Есть множество способов формирования портфелей, статья не претендует на универсальность, поэтому здесь будут рассмотрены несколько простых методов и примеры алгоритмов. В частности, предлагается в качестве основы использовать метод наименьших квадратов (МНК) и метод главных компонент (МГК). Более подробно об этих методах можно прочитать здесь:

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

Иллюстрация к трём типам портфелей (тренд, флэт, функция):


Портфель можно представить в виде уравнения следующего вида:

A*k1 + B*k2 + C*k3 + ... = F

где

A, B, C ... — это временные ряды, соответствующие инструментам в портфеле

k1, k2, k3 ... — это лоты при инструментах (положительные — покупка, отрицательные — продажа)

F — целевая функция (задаётся значениями в точках временного ряда)

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

Целевая функция определяет вид графика, на который будет похож график портфеля. Значения целевой функции необходимо предварительно рассчитать в каждой точке соответствующим образом. Например, в случае, когда создается простой растущий портфель (трендовый портфель), целевая функция будет иметь значения: 0, 1*S, 2*S, 3*S и так далее, где S — шаг приращения, денежная величина, на которую должен прирастать портфель с каждым баром на заданном интервале. Алгоритм МНК складывает временные ряды A, B, C, ... так, что их общая сумма стремится повторить график целевой функции. Для этого алгоритм МНК минимизирует сумму квадратов отклонений между суммой рядов и целевой функцией. Это стандартная задача статистики, детальное понимание работы алгоритма не обязательно, так как можно воспользоваться готовой библиотекой.

Особая ситуация возникает, когда целевая функция содержит только нулевые значения (флэтовый портфель). В этом случае необходимо ввести дополнительное ограничение на сумму коэффициентов, например: k1 + k2 + k3 + ... = 1, чтобы обойти вырожденное решение регрессионного уравнения с нулевыми корнями. Альтернативный подход: перенести один член уравнения в правую сторону, который сам станет целевой функцией и получит коэффициент -1, а оставшиеся члены будут оптимизироваться как обычно. В этом случае приравниваем корзину инструментов к одному выбранному инструменту, то есть создаём портфель спредового типа. Наконец, можно использовать для формирования таких портфелей более продвинутый алгоритм МГК, который через матрицу ковариаций инструментов рассчитывает вектор коэффициентов, соответствующий гиперплоскости сечения облака точек с минимальной остаточной дисперсией портфеля. Здесь снова можно не беспокоиться о детальном понимании алгоритма, так как можно воспользоваться готовой библиотекой.


Алгоритмы

Теперь описанные идеи предстоит реализовать на языке MQL. Для работы будет использоваться известная математическая библиотека ALGLIB, адаптированная для MT4. Иногда возникают вопросы с её установкой, поэтому стоит остановиться на этом немного подробнее. Если на компьютере установлено несколько терминалов, то очень важно определить правильную папку данных, так как компилятор не увидит библиотеку, если она лежит в папке данных другого терминала.

Установка библиотеки ALGLIB:

  1. скачиваем библиотеку (https://www.mql5.com/ru/code/11077), распаковываем zip-файл;
  2. открываем папку include, внутри будет папка Math;
  3. запускаем терминал МetaТrader 4, в который требуется поставить библиотеку;
  4. выбираем команду меню: Файл — Открыть каталог данных, откроется папка данных терминала;
  5. открываем в этой папке подпапку MQL4 и далее подпапку Include;
  6. из распакованной библиотеки копируем папку Math в папку Include терминала;
  7. проверяем, что получилось: файлы *.mhq должны быть внутри MQL4\Include\Math\Alglib.
Первый ключевой этап: перевод временных рядов из ценовых пунктов в валюту депозита. Для этой задачи потребуется написать специальную функцию, которая будет вычислять значение стоимости контракта в произвольный момент времени. Стандартная функция MarketInfo для этого не вполне подходит, ведь с её помощью можно получить корректную стоимость пункта только для последнего бара графика, а в истории неизбежно возникнут отклонения, потому что стоимость пункта у некоторых инструментов постоянно меняется. Очень важно безошибочно конвертировать ряды данных, иначе могут быть серьёзные перекосы в портфеле.

Пример функции, рассчитывающей стоимость контракта, приведён ниже:

double ContractValue(string symbol,datetime time,int period)
  {
   double value=MarketInfo(symbol,MODE_LOTSIZE);                     // получаем размер лота
   string quote=SymbolInfoString(symbol,SYMBOL_CURRENCY_PROFIT);     // получаем валюту расчётов

   if(quote!="USD")                                                  // если валюта расчётов не USD, то выполняем конверсию
     {
      string direct=FX_prefix+quote+"USD"+FX_postfix;                // формируем прямую котировку для валюты расчётов
      if(MarketInfo(direct,MODE_POINT)!=0)                           // проверяем её существование
        {
         int shift=iBarShift(direct,period,time);                    // находим бар по времени
         double price=iClose(direct,period,shift);                   // получаем котировку этого бара
         if(price>0) value*=price;                                   // рассчитываем стоимость
        }
      else
        {
         string indirect=FX_prefix+"USD"+quote+FX_postfix;           // формируем обратную котировку для валюты расчётов
         int shift=iBarShift(indirect,period,time);                  // находим бар по времени
         double price=iClose(indirect,period,shift);                 // получаем котировку этого бара
         if(price>0) value/=price;                                   // рассчитываем стоимость
        }
     }

   if(Chart_Currency!="USD")                                         // если целевая валюта не USD, то выполняем конверсию
     {
      string direct=FX_prefix+Chart_Currency+"USD"+FX_postfix;       // формируем прямую котировку для целевой валюты
      if(MarketInfo(direct,MODE_POINT)!=0)                           // проверяем её существование
        {
         int shift=iBarShift(direct,period,time);                    // находим бар по времени
         double price=iClose(direct,period,shift);                   // получаем котировку этого бара
         if(price>0) value/=price;                                   // рассчитываем стоимость
       }
      else
        {
         string indirect=FX_prefix+"USD"+Chart_Currency+FX_postfix;  // формируем обратную котировку для целевой валюты
         int shift=iBarShift(indirect,period,time);                  // находим бар по времени
         double price=iClose(indirect,period,shift);                 // получаем котировку этого бара
         if(price>0) value*=price;                                   // рассчитываем стоимость
        }
     }

   return(value);
  }

Эта функция будет постоянно использоваться в дальнейшем. Она работает не только с валютными парами, но и с индексами, фьючерсами и с CFD, а также учитывает префиксы и суффиксы для валютных пар (FX_prefix, FX_postfix), которые используют некоторые брокеры.  Результат переводится в целевую валюту Chart_Currency. Если возвращаемое значение функции умножить на текущую цену инструмента, то получится стоимость одного лота этого инструмента. Просуммировав стоимости всех контрактов в портфеле, с учётом лотов, получаем стоимость всего портфеля. Если значение функции умножить на разницу цен во времени, то получим прибыль или убыток, полученные в результате этого изменения цен.

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

double EQUITY[][100];     // первое измерение для баров, второе измерение для инструментов

Сначала запоминаем начальные цены для всех инструментов (на левой границе расчётного интервала), затем в каждой точке расчётного интервала вычисляем разницу начальных и конечных цен, умножаем на стоимость контракта. Каждый раз в цикле сдвигаемся на один интервал времени вправо:

   for(int i=0; i<variables+constants; i++)                              // цикл по инструментам портфеля (переменным и константам модели)
     {
      int shift=iBarShift(SYMBOLS[i],Timeframe,zero_time);               // получаем номер бара по времени для нулевой точки
      opening[i]=iClose(SYMBOLS[i],Timeframe,shift);                     // получаем цену этого бара и сохраняем в массиве
     }

   points=0;                                                             // будем считать точки в этой переменной
   datetime current_time=zero_time;                                      // начинаем цикл с нулевой точки
   while(current_time<=limit_time)                                       // проходим по меткам времени в интервале оптимизации
     {
      bool skip_bar=false;
      for(int i=0; i<variables+constants; i++)                           // цикл по инструментам портфеля (переменным и константам модели)
         if(iBarShift(SYMBOLS[i],Timeframe,current_time,true)==-1)       // проверяем существование бара для инструмента
            skip_bar=true;                                               // если бар не существует, то пропускаем его для остальных инструментов
      if(!skip_bar)                                                      // продолжаем работу, если бар синхронизирован между всеми инструментами
        {
         points++;                                                       // увеличиваем число точек на единицу
         TIMES[points-1]=current_time;                                   // запоминаем метку времени
         for(int i=0; i<variables+constants; i++)                        // основной цикл расчёта прибыли по всем инструментам в точке
           {
            int shift=iBarShift(SYMBOLS[i],Timeframe,current_time);      // получаем номер бара по времени
            closing[i]=iClose(SYMBOLS[i],Timeframe,shift);               // получаем цену этого бара
            double CV=ContractValue(SYMBOLS[i],current_time,Timeframe);  // рассчитываем стоимость контракта
            profit[i]=(closing[i]-opening[i])*CV;                        // рассчитываем прибыль по разнице цен и стоимости
            EQUITY[points-1,i]=profit[i];                                // сохраняем значение прибыли
           }
        }
      current_time+=Timeframe*60;                                        // сдвигаемся в следующий интервал времени
     }

В этом фрагменте кода: zero_time — время левой границы расчётного интервала, limit_time — время правой границы расчётного интервала, Timeframe — количество минут в одном баре рабочего таймфрейма, points — общее число найденных точек в расчётном интервале. В данном примере используется правило строгого соответствия меток времени, и если хотя бы на одном инструменте отсутствует бар для определённой метки времени, то позиция пропускается и делается сдвиг к следующей позиции. Контроль меток времени очень важен для предварительной подготовки данных, так как рассинхронизация данных на разных инструментах может привести к серьёзным искажениям в портфеле.

Пример подготовленных данных для портфеля из трёх инструментов и независимой функции (парабола квадратного корня):

DATE/TIME AUDJPY GBPUSD EURCAD MODEL
03.08.16 14:00 0 0 0 0
03.08.16 15:00 -61,34 -155 -230,06 10,21
03.08.16 16:00 -82,04 -433 -219,12 14,43
03.08.16 17:00 -39,5 -335 -356,68 17,68
03.08.16 18:00 147,05 -230 -516,15 20,41
03.08.16 19:00 169,73 -278 -567,1 22,82
03.08.16 20:00 -14,81 -400 -703,02 25
03.08.16 21:00 -109,76 -405 -753,15 27
03.08.16 22:00 -21,74 -409 -796,49 28,87
03.08.16 23:00 51,37 -323 -812,04 30,62
04.08.16 00:00 45,43 -367 -753,36 32,27
04.08.16 01:00 86,88 -274 -807,34 33,85
04.08.16 02:00 130,26 -288 -761,16 35,36
04.08.16 03:00 321,92 -194 -1018,51 36,8
04.08.16 04:00 148,58 -205 -927,15 38,19
04.08.16 05:00 187 -133 -824,26 39,53
04.08.16 06:00 243,08 -249 -918,82 40,82
04.08.16 07:00 325,85 -270 -910,46 42,08
04.08.16 08:00 460,02 -476 -907,67 43,3
04.08.16 09:00 341,7 -671 -840,46 44,49


Теперь, имея подготовленные данные, можно отправить их в модель оптимизации. Оптимизацию будем выполнять при помощи функций LRBuildZ, LSFitLinearC и PCABuildBasis из библиотеки ALGLIB. Описание этих функций (довольно скупое, но в целом понятное) можно найти внутри самой библиотеки и на официальном сайте проекта здесь: http://www.alglib.net/dataanalysis/linearregression.php и здесь: http://www.alglib.net/dataanalysis/principalcomponentsanalysis.php.

Для начала работы с библиотекой нужно подключить её:

#include <Math\Alglib\alglib.mqh>

Далее для каждой модели оптимизации нужно прописать свой фрагмент кода с учётом особенностей модели. Сначала рассмотрим пример построения трендовой модели:

   if(Model_Type==trend)
     {
      int info,i,j;                                                                                  // определяем рабочие переменные
      CLinearModelShell LM;                                                                          // определяем специальный объект-модель
      CLRReportShell AR;                                                                             // определяем специальный объект-отчёт
      CLSFitReportShell report;                                                                      // определяем ещё один объект
      CMatrixDouble MATRIX(points,variables+1);                                                      // определяем матрицу для хранения всех данных
      if(Model_Growth==0) { Alert("Zero model growth!"); error=true; return; }                       // проверяем корректность параметров модели
      for(j=0; j<points; j++)                                                                        // рассчитываем целевую функцию по точкам интервала оптимизации
        {
         double x=(double)j/(points-1)-Model_Phase;                                                  // рассчитываем значение абсциссы
         if(Model_Absolute) x=MathAbs(x);                                                            // делаем модель симметричной если необходимо
         MODEL[j]=Model_Growth*x;                                                                    // рассчитываем значение ординаты
        }
      double zero_shift=-MODEL[0]; if(zero_shift!=0) for(j=0; j<points; j++) MODEL[j]+=zero_shift;   // сдвигаем модель по вертикали к нулевой точке
      for(i=0; i<variables; i++) for(j=0; j<points; j++) MATRIX[j].Set(i,EQUITY[j,i]);               // загружаем данные инструментов в матрицу
      for(j=0; j<points; j++) MATRIX[j].Set(variables,MODEL[j]);                                     // загружаем данные модели в матрицу
      CAlglib::LRBuildZ(MATRIX,points,variables,info,LM,AR);                                         // запускаем расчёт регрессии
      if(info<0) { Alert("Error in regression model!"); error=true; return; }                        // проверяем результат
      CAlglib::LRUnpack(LM,ROOTS,variables);                                                         // получаем корни уравнения
     }

При первом прочтении это может показаться сложным, но в основе всё просто. Сначала рассчитывается функция линейного тренда и её значения помещаются в массив MODEL, при этом параметр Model_Growth задает величину прироста на весь интервал расчёта (насколько должен вырасти портфель в валюте депозита). Параметры Model_Absolute и Model_Phase опциональные и на данном этапе пока неважны. Для расчётов создается матрица MATRIX, в которую загружаются данные виртуальной прибыли всех контрактов из массива EQUITY, а также значения целевой функции из массива MODEL в последний ряд этой матрицы. Число независимых переменных регрессионного уравнения хранится в переменной variables. Далее вызывается функция LRBuildZ, которая выполняет расчёт, после чего корни регрессионного уравнения записываются в массив ROOTS с помощью функции LRUnpack. Вся сложная математика находится внутри библиотеки, можно пользоваться уже готовыми функциями. Сложность здесь чисто техническая и заключается в том, чтобы корректно прописать все вызовы и не потерять данные при подготовке.

Этот же фрагмент кода можно использовать для любой произвольно заданной функции, достаточно заменить содержимое массива MODEL на свою целевую функцию. Вот, например, расчёт параболической функции квадратного корня:

      for(j=0; j<points; j++)                               // рассчитываем целевую функцию по точкам интервала оптимизации
        {
         double x=(double)j/(points-1)-Model_Phase;         // рассчитываем значение абсциссы
         int sign=(int)MathSign(x);                         // определяем знак числа
         if(Model_Absolute) sign=1;                         // делаем модель симметричной, если необходимо
         MODEL[j]=sign*Model_Growth*MathSqrt(MathAbs(x));   // рассчитываем значение ординаты
        }

А здесь пример более сложной функции, сумма линейного тренда и гармонических колебаний:

      for(j=0; j<points; j++)                                     // рассчитываем целевую функцию по точкам интервала оптимизации
        {
         double x=(double)j/(points-1)*Model_Cycles-Model_Phase;  // рассчитываем значение абсциссы
         if(Model_Absolute) x=MathAbs(x);                         // делаем модель симметричной, если необходимо
         MODEL[j]=Model_Amplitude*MathSin(2*M_PI*x);              // рассчитываем значение ординаты
        }

В последнем примере можно регулировать величину тренда с помощью параметра Model_Growth и амплитуду колебаний с помощью параметра Model_Amplitude, при этом задавать количество циклов колебаний с помощью параметра Model_Cycles и делать смещение фазы колебаний с помощью параметра Model_Phase.

Дополнительно для корректности расчётов необходимо делать смещение по вертикали, чтобы в нулевой точке функция принимала нулевое значение:

   double zero_shift=-MODEL[0];   // считываем значение модели в нулевой точке
   if(zero_shift!=0)              // проверяем, что это не нуль
      for(j=0; j<points; j++)     // проходим по всем точкам интервала
         MODEL[j]+=zero_shift;    // смещаем все точки модели

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

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

   for(i=0; i<variables; i++)                    // цикл по инструментам оптимизируемой корзины
      for(j=0; j<points; j++)                    // цикл по точкам расчётного интервала
         MATRIX[j].Set(i,EQUITY[j,i]);           // загружаем значения инструментов оптимизируемой корзины в колонки матрицы
   for(i=variables; i<variables+constants; i++)  // цикл по инструментам эталонной корзины
      for(j=0; j<points; j++)                    // цикл по точкам расчётного интервала
         MODEL[j]+=EQUITY[j,i]*LOTS[i];          // загружаем значения инструментов эталонной корзины в последнюю колонку матрицы

Пример расчёта флэтового портфеля, где функция LSFitLinearC делает портфель максимально симметричным вокруг нуля в пределах расчётного интервала:

   if(Model_Type==fitting)
     {
      int info,i,j;                                                                        // определяем рабочие переменные
      CLSFitReportShell report;                                                            // определяем специальный объект-модель
      CMatrixDouble CONSTRAIN(1,variables+1);                                              // определяем матрицу линейных ограничений
      CMatrixDouble MATRIX(points,variables);                                              // определяем матрицу для хранения всех данных
      ArrayInitialize(MODEL,0);                                                            // заполняем модель нулями
      CONSTRAIN[0].Set(variables,1);                                                       // устанавливаем единственное ограничение
      for(i=0; i<variables; i++) CONSTRAIN[0].Set(i,1);                                    // сумма корней должна равняться единице
      for(i=0; i<variables; i++) for(j=0; j<points; j++) MATRIX[j].Set(i,EQUITY[j,i]);     // загружаем данные инструментов в матрицу
      CAlglib::LSFitLinearC(MODEL,MATRIX,CONSTRAIN,points,variables,1,info,ROOTS,report);  // рассчитываем оптимизационную модель по МНК
      if(info<0) { Alert("Error in linear fitting model!"); error=true; return; }          // проверяем результат
     }

И ещё один важный пример расчёта флэтового портфеля с минимальной дисперсией по методу МГК. Здесь функция PCABuildBasis рассчитывает коэффициенты так, чтобы график портфеля был максимально сжатым в расчётном интервале:

   if(Model_Type==principal)
     {
      int info,i,j;                                                                        // определяем рабочие переменные
      double VAR[];                                                                        // определяем массив дисперсий
      ArrayResize(VAR,variables);                                                          // приводим массив к нужной размерности
      CMatrixDouble VECTOR(variables,variables);                                           // определяем матрицу векторов коэффициентов
      CMatrixDouble MATRIX(points,variables);                                              // определяем матрицу для хранения всех данных
      for(i=0; i<variables; i++) for(j=0; j<points; j++) MATRIX[j].Set(i,EQUITY[j,i]);     // загружаем данные инструментов в матрицу
      CAlglib::PCABuildBasis(MATRIX,points,variables,info,VAR,VECTOR);                     // рассчитываем ортогональный базис по МГК
      if(info<0) { Alert("Error in principal component model!"); error=true; return; }     // проверяем результат
      for(i=0; i<variables; i++) ROOTS[i]=VECTOR[i][variables-1];                          // выгружаем оптимальные коэффициенты
     }

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

1 Расчёт виртуальной прибыли для инструментов портфеля с единичными лотами
2 Расчёт значений целевой функции
3 Алгоритм оптимизации лотов
4 Нормализация объёмов портфеля
5 Расчёт графика и торговые операции с портфелем

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

Простой пример алгоритма нормализации по стоимости портфеля:

      double total_value=0;                                                                         // определяем переменную для стоимости портфеля
      for(int i=0; i<variables+constants; i++)                                                      // проходим по всем инструментам портфеля
         total_value+=closing[i]*ContractValue(SYMBOLS[i],limit_time,Timeframe)*MathAbs(LOTS[i]);   // рассчитываем и суммируем компоненты стоимости

      if(total_value==0) { Alert("Zero portfolio value!"); error=true; return; }                    // проверяем, что в итоге не получили нуль
      scale_volume=Portfolio_Value/total_value;                                                     // находим коэффициент масштабирования

      for(int i=0; i<variables+constants; i++)                                                      // снова проходим по всем инструментам портфеля
         LOTS[i]=NormalizeDouble(LOTS[i]*scale_volume,Lots_Digits);                                 // приводим лоты к требуемой суммарной стоиомсти

Здесь стоимость портфеля приравнивается к требуемой через пропорции. Portfolio_Value — требуемая стоимость портфеля, total_value — общая стоимость портфеля с коэффициентами по умолчанию, scale_volume — коэффициент масштабирования, Lots_Digits — разрядность лотов, LOTS — массив значений лотов, пригодных для торговли.

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

Инструмент AUDJPY GBPUSD EURCAD
Лот -0,07 -0,11 -0,11

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

   for(int j=draw_begin; j>=draw_end; j--)                                                   // цикл по барам графика в интервале отрисовки
     {
      double profit=0;                                                                       // начинаем с нулевого значения
      for(int i=0; i<variables; i++)                                                         // проходим по всем инструментам
        {
         if(Fast_Period>0 && Slow_Period>0 && number!=N_TOTAL)                               // выполняем второстепенные проверки
           {
            int shift=iBarShift(SYMBOLS[i],Period(),Time[j]);                                // получаем номер бара по времени
            double CV=ContractValue(SYMBOLS[i],Time[j],Period());                            // рассчитываем стоимость контракта
            double fast=iMA(SYMBOLS[i],Period(),Fast_Period,0,MODE_SMA,PRICE_CLOSE,shift);   // рассчитываем медленную среднюю
            double slow=iMA(SYMBOLS[i],Period(),Slow_Period,0,MODE_SMA,PRICE_CLOSE,shift);   // рассчитываем быструю среднюю
            profit+=(fast-slow)*CV*LOTS[i];                                                  // рассчитываем осцилляторную модель
           }
         else
           {
            int shift=iBarShift(SYMBOLS[i],Period(),Time[j]);                                // получаем номер бара по времени
            double closing=iClose(SYMBOLS[i],Period(),shift);                                // получаем цену инструмента в точке
            double CV=ContractValue(SYMBOLS[i],Time[j],Period());                            // рассчитываем стоимость контракта
            profit+=(closing-OPENINGS[i])*CV*LOTS[i];                                        // рассчитываем прибыль по разнице цен и стоимости
           }
        }
      BUFFERS[number].buffer[j]=NormalizeDouble(profit,2);                                   // сохраняем значение прибыли в индикаторном массиве
     }

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

Пример построения графика портфеля (подвальное окно индикатора) с наложенным графиком целевой функции:

 

В этом примере в качестве целевой функции используется парабола квадратного корня, которая сделана симметричной относительно начала координат (параметр Model_Absolute=true). Границы расчётного интервала отмечены на графике красными пунктирными линиями, график портфеля стремится двигаться вдоль линии целевой функции, причём, как легко заметить, и внутри и вне расчётного интервала.

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

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

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

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

Пример простого минималистичного интерфейса для портфельного советника:

 

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

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

struct MASSIVE                     // определяем структуру с множеством типов данных внутри
  {
   string symbol[MAX_SYMBOLS];     // текстовый массив для инструментов портфеля
   double lot[MAX_SYMBOLS];        // числовой массив для лотов
   string formula;                 // строка с формулой портфеля
   double direction;               // признак направления портфеля
   double filter;                  // признак отфильтрованности
  };

MASSIVE PORTFOLIOS[DIM_SIZE];      // создаём массив структур для группы портфелей

В данном фрагменте кода DIM_SIZE задаёт максимальный размер для хранения портфелей. Сама структура устроена следующим образом: symbol — массив инструментов портфеля, lot — массив лотов для инструментов портфеля, formula — текстовая строка с формулой портфеля, direction — направление для портфеля (лонг или шорт), filter — признак фильтра (включён/исключён). Использование массива структур удобнее и логичнее, чем отдельные массивы.

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

struct STREAM{double buffer[];};     // определяем структуру, содержащую числовой массив
STREAM BUFFERS[DIM_SIZE];            // создаем массив структур

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

1 Расчёт графиков отдельных портфелей
2 Совмещение пучка портфелей в нулевой точке
3 Переворот портфелей относительно нулевого уровня
4 Применение фильтра к пучку портфелей
5 Суммаризация — формирование суперпортфеля

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

Следующая картинка иллюстрирует эти операции:

 

Совмещение портфелей достигается за счёт вертикального сдвига. Переворот портфеля достигается умножением на -1. А применение фильтра реализуется сортировкой и выборкой по значениям. Детальное описание этих алгоритмов здесь не приводится, так как оно содержало бы много рутинного кода.

Пример пучка портфелей, построенного по вышеописанным принципам:

 

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

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


Примеры реализации

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

  • Portfolio Modeller — построитель-оптимизатор портфелей. Имеет несколько типов моделей оптимизации с настраиваемыми параметрами, можно дописывать собственные модели и целевые функции, есть базовые средства для технического анализа портфелей, различные опции форматирования графика.

  • Portfolio Multigraph — генератор портфельных пучков, с теми же моделями и параметрами, с дополнительными опциями для трансформации и фильтрации портфелей и составления суперпортфеля.

  • Portfolio Manager — советник для работы с портфелями и суперпортфелями, работает в связке с портфельным индикатором, позволяет открывать и управлять синтетическими позициями, имеет функциональность корректировки портфелей, имеет режим авто-торговли на основе графических линий виртуальных приказов.

Ссылка для скачивания: https://www.mql5.com/ru/code/11859


Торговые стратегии

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

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

Долгосрочный портфель Уоррена Баффета:

 

Для работы с классическими инвестиционными портфелями нужно очень внимательно оценивать текущее состояние активов, чтобы покупать активы не на пике роста, а на снижении.

Первым и самым простым вариантом спекулятивной портфельной торговли был парный трейдинг — создание спреда из двух коррелированных инструментов. На рынке Forex этот подход существенно ограничен, так как даже сильно коррелированные валютные пары не имеют коинтеграции, и как следствие, могут значительно разбегаться через некоторое время. Эта ситуация называется "спред порвался". Кроме того, поскольку в спред обычно попадают пары с общей валютой, то такой парный трейдинг превращается в торговлю синтетическим кросс-курсом. Парный трейдинг в таком виде — это очень плохая идея. Открыв встречные позиции по спреду, иногда придётся ждать очень долго, прежде чем кривые снова сойдутся.

Пример хорошо коррелированных пар и их постепенный и неизбежный разбег:

 

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

Пример поведения многостороннего спреда на новостях:

 

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

Тупиковая ветвь спред-трейдинга — многосторонний лок, когда выбираются циклически взаимосвязанные валютные пары (например, EURUSD-GBPUSD-EURGBP) и из них составляется сбалансированный спред. Спред получается идеальный, но торговать им невозможно, так как суммарные спреды и комиссии слишком велики. Попытка немного разбалансировать лоты приводит к тому, что график начинает приобретать трендовые составляющие, что противоречит спредовой торговле, а издержки всё ещё остаются большими. Такой подход совершенно бессмысленный.

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

 

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

Пример хорошей трендовой модели:

 

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

Пример резкого завершения тренда:

 

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

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

Пример выхода из коридора короткопериодного спреда, отмечены границы коридора спреда:

 

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

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

Пример разворота трендового портфеля, показаны внешняя и внутренняя трендовые линии:

 

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

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

Подробнее о свойствах рыночных распределений можно почитать следующие книги Эдгара Петерса:

  • "Хаос и порядок на рынках капитала"
  • "Фрактальный анализ финансовых рынков"

Пример ухода портфеля от параболической функции:

 

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

Иллюстрация двойственной природы тренда и флэта, трендовая модель на большом масштабе напоминает неровный флэт:

 

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

Далее рассмотрим некоторые свойства портфельных пучков и их возможные применения в торговых системах.

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

Пример расширяющегося пучка портфелей:

 

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

Пример сужающегося пучка портфелей:

 

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

Пример торгового сетапа на продолжение движения с переворотом и смещением пучка:

 

Пример торгового сетапа на возврат по мультитрендовой модели:

 

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

Пример многократного перекручивания пучка:

 

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

  • торговля одной синтетической позицией (простейший случай)
  • дробление объёмов (растянутый вход по уровням)
  • добавление в растущий портфель (пирамидинг по тренду)
  • добавление в просевший портфель (усреднение позиций)
  • добавление в портфель после корректировки (метод добивания)
  • добавление в портфель после переворота (экспансивная стратегия)
  • добавление в новые портфели (консолидация портфелей)
  • комбинированный подход (сочетание нескольких подходов)

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

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

В мультипортфельной торговле могут применяться различные стратегии выхода, в частности:

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

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


Заключение

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

Недостатки портфельного трейдинга: неприменимы стандартные отложенные приказы, больше требования к минимальному объёму, больше спреды на графиках М30 и ниже, внутридневной скальпинг затруднён, на графике портфеля нет OHLC-данных, не все индикаторы могут применяться к портфелям.

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




Последние комментарии | Перейти к обсуждению на форуме трейдеров (24)
Vasily Belozerov
Vasily Belozerov | 24 нояб. 2017 в 10:53

Приветствую!

1. Научный подход: выдвигается гипотеза, доказывается и опровергается. Если не опровергается, становится аксиомой. Я опроверг Вашу гипотезу. Зачем иронизировать?

2. Опровержение не для Вас, а для читателей Вашей статьи.

3. Цитирую Вас: "Портфель — набор позиций по нескольким торговым инструментам". А если по одному инструменту 10 разных методов торговли, является ли это портфелем? Если да, напишите, пожалуйста, про это статью.

transcendreamer
transcendreamer | 24 нояб. 2017 в 11:49
Vasily Belozerov:

Приветствую!

1. Научный подход: выдвигается гипотеза, доказывается и опровергается. Если не опровергается, становится аксиомой. Я опроверг Вашу гипотезу. Зачем иронизировать?

2. Опровержение не для Вас, а для читателей Вашей статьи.

3. Цитирую Вас: "Портфель — набор позиций по нескольким торговым инструментам". А если по одному инструменту 10 разных методов торговли, является ли это портфелем? Если да, напишите, пожалуйста, про это статью.


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

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

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

fxsaber
fxsaber | 8 авг. 2019 в 14:07

Если в гугле набрать "AlgorithmicEA", то можно выйти на мониторинг синтетического инструмента, где видна история торгов. Сам не изучал.

transcendreamer
transcendreamer | 9 авг. 2019 в 14:57
fxsaber:

Если в гугле набрать "AlgorithmicEA", то можно выйти на мониторинг синтетического инструмента, где видна история торгов. Сам не изучал.

Спасибо, будет интересно посмотреть...

Виталий Шусть
Виталий Шусть | 12 авг. 2021 в 00:15
Как растчитывается лоты для торговли спредом ? Я говорю про то когда переключатель стоит на спред то лоты пересчитываются но не знаю по какой формуле ????
Сравнение MQL5 и QLUA - почему торговые операции в MQL5 до 28 раз быстрее? Сравнение MQL5 и QLUA - почему торговые операции в MQL5 до 28 раз быстрее?
Многие трейдеры зачастую не задумываются над тем, как быстро доходит их заявка до биржи, как долго она там исполняется, и когда наконец-то торговый терминал трейдера узнает о результате торговой операции. Мы обещали дать сравнение скорости торговых операций, ведь никто до нас не делал таких замеров с помощью программ на MQL5 и QLUA.
Рецепты MQL5 - Торговые сигналы скользящих каналов Рецепты MQL5 - Торговые сигналы скользящих каналов
В статье представлен процесс разработки и реализации класса-сигнальщика на основе скользящих каналов. За каждой из версий сигнала следует торговая стратегия с результатами тестирования. Используются классы Стандартной библиотеки для создания производных классов.
LifeHack для трейдера: "Тихая" оптимизация или Строим распределения трейдов LifeHack для трейдера: "Тихая" оптимизация или Строим распределения трейдов
Анализ торговой истории и построение HTML графиков распределения результатов торговли в зависимости от времени входа в позицию. Графики отображаются в трех разрезах – по часам, дням недели и месяцам.
Работа с корзинами валютных пар на рынке Форекс Работа с корзинами валютных пар на рынке Форекс
В статье рассматриваются вопросы о том, как разбить валютные пары по группам - корзинам; как получить данные о состоянии таких корзин (например, перекупленности и перепроданности); какие индикаторы могут предоставить такие данные; наконец, о том, как можно применить полученную информацию в практическом трейдинге.