Pull to refresh

Как устроены технические индикаторы на фондовых рынках

Reading time5 min
Views25K
Любой кто когда-нибудь интересовался фондовыми или криптовалютными рынками видел эти дополнительные линии. И вы наверно слышали мнения от матерых трейдеров о том, что они не работают и как они не используют ничего. Но многим они очень помогают и мой торговый терминал, в который я лениво смотрю раз в день, выглядит примерно как на картинке ниже.

Как же все таки они устроены? И кому это может быть полезно? Вам определенно с этим следует ознакомиться, если:

  1. Вы ими пользуетесь в своей торговле
  2. Вы планируете написать торгового робота
  3. Вы хотите реализовать торговую стратегию сами

технические индикаторы

Технический индикатор, это чаще всего оконная, весовая или рекуррентная функция от цен и объемов, которые приходят с биржи в формате массива свеч TOHLCV (unix time, open, high, low, close, volume). Так же могут использоваться различные фильтрации, максимумы-минимумы или другие индикаторы как основа для последующих вычислений.

Скользящая средняя (SMA)

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

function sma($close, window) {
  return rolling(x => mean(x), window, $close);
}

где функция mean() это среднее значение, параметр window — размер окна, а rolling() это комбинация оконной функции, которая для каждой текущей ячейки массива выдает массив из последних n элементов, и операции, которая сворачивает окно в число.

function rolling(operation, window, array) {
  let result = [];
  for (let i = 0; i < array.length; i++) {
    if (i + 1 < window) {
      result.push(NaN);
    } else {
      result.push(operation(array.slice(i + 1 - window, i + 1)));
    }
  }
  return result;
}

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

Скользящая средняя (SMA)

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

Среднеквадратичное отклонение (STDEV)

Если мы заменим в предыдущем варианте функцию mean() на корень из дисперсии sd(), то получим уже скользящее среднеквадратичное отклонение.

function stdev($close, window) {
  return rolling(x => sd(x), window, $close);
}

Дисперсия считается обычным всем известным способом, чаще всего без коррекции Бесселя. Так же используется именно корень из дисперсии, так как сама дисперсия измеряется в квадратных рублях/долларах.

Полосы Боллинджера (BB)

Таким образом мы уже получили два базовых индикатора, которые уже можно комбинировать и получать новые. Например, если поточечно сложить скользящую среднюю и среднеквадратичное отклонение, при этом домножив на 2, то мы получим верхнюю часть полосы Боллинджера, а если вычесть — нижнюю.

Полосы Боллинджера (BB)

В коде это будет выглядеть так

function bb($close, window, mult) {
  let middle = sma($close, window);
  let upper = pointwise((a, b) => a + b * mult, middle, stdev($close, window));
  let lower = pointwise((a, b) => a - b * mult, middle, stdev($close, window));
  return { lower : lower, upper : upper};
}

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

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

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


Экспоненциально взвешенная скользящая средняя (EMA)

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

$\bar x = \frac{\sum x_i}{N} = \frac{\sum 1 \cdot x_i}{\sum 1} \quad \Rightarrow \quad \widetilde{x} = \frac{\sum x_i w_i}{\sum w_i}$


если $w_i=q^i$ и выбрать какую то константу $q$ меньше единицы, то мы получим бесконечно убывающий вес, если при этом складывать цены начиная с самой новой.

весовые функции

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

$ 1+q+q^2+...+q^n \underset{n\to \infty}{\underset{q < 0}{\approx}} \frac{1}{1-q}\\ \mathrm{EMA}_{curr} = \frac{\sum x_i q^i}{\sum q^i} \approx (1-q) \sum x_i q^i\\ \mathrm{EMA}_{next} = \frac{x_{next} +q \cdot \sum x_i q^i}{1 + q \cdot \sum q^i} = (1-q) \cdot \left[x_{next}+q \cdot \sum x_i q^i\right]\\ \mathrm{EMA}_{next} = (1-q) \cdot x_{next} + q \cdot \mathrm{EMA}_{curr}$


В итоге нам нужно выбрать какое то значение $\alpha=1-q$ как константу сглаживания. Можно показать, что если взять $\alpha = 2 / (N+ 1)$ центр масс у весовых графиков EMA и SMA выше становится одинаковым. В коде все это выглядит намного проще.

function ema($close, window, weight = null) {
  weight = weight ? weight : 2 / (window + 1);
  let ema = [ mean($close.slice(0, window)) ];
  for (let i = 1; i < $close.length; i++) {
    ema.push($close[i] * weight + ema[i - 1] * (1 - weight));
  };
  return ema;
}

В целом эта та же скользящая средняя, но более чувствительная.

Экспоненциально взвешенная скользящая средняя (EMA)

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

Cхождение/расхождение скользящих средних (MACD)

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

Cхождение/расхождение скользящих средних (MACD)

Формула расчета довольно простая, берутся две ema с динным и коротким окном, например в 26 и 12 единицы, и вычитаются, полученная линия и будет искомым индикатором. Взяв от этой разности еще одну ema c шагом в 3 единицы получим сигнальную линию. Гистограмма, которую Джеральд добавил позже высчитывается разницей между двумя предыдущими результатами и по сути является средневзвешенной производной.

function macd($close, wshort, wlong, wsig) {
  let line = pointwise((a, b) => a - b, ema($close, wshort), ema($close, wlong));
  let signal = ema(line, wsig);
  let hist = pointwise((a, b) => a - b, line, signal);
  return { line : line, signal : signal, hist : hist };
}

Тестирование индикаторов, нормированная среднеквадратичная ошибка

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

$\mathrm{NRMSE} = \left. \sqrt{\frac{\sum(\hat x_i - x_i)^2} {N}} \middle/ (\max{x_i} - \min{x_i}) \right.$


лучше всего работает, как при малых величинах, так и при больших. Например биткоин в долларах может стоить 20000$ и разница в 10$ не критична, в то же время один альткоин может исчисляться несколькими сатошами.

function nrmse(f, g) {
  let sqrDiff = pointwise((a, b) => (a - b) * (a - b), f, g);
  return Math.sqrt(mean(sqrDiff)) / (Math.max(...f) - Math.min(...f));
}

Заключение

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

Используемые источники

1. StockCharts — cписок алгоритмов с проверочными данными в таблицах
2. Cryptowatch — хорошо настроенные параметры индикаторов
3. Github — исходный код
Tags:
Hubs:
Total votes 41: ↑37 and ↓4+33
Comments29

Articles