[Из песочницы] Как устроены технические индикаторы на фондовых рынках
Любой кто когда-нибудь интересовался фондовыми или криптовалютными рынками видел эти дополнительные линии. И вы наверно слышали мнения от матерых трейдеров о том, что они не работают и как они не используют ничего. Но многим они очень помогают и мой торговый терминал, в который я лениво смотрю раз в день, выглядит примерно как на картинке ниже.
Как же все таки они устроены? И кому это может быть полезно? Вам определенно с этим следует ознакомиться, если:
- Вы ими пользуетесь в своей торговле
- Вы планируете написать торгового робота
- Вы хотите реализовать торговую стратегию сами
Индикаторы, это чаще всего оконная, весовая или рекуррентная функция от цен и объемов, которые приходят с биржи в формате массива свеч 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;
}
Скользящая средняя является запаздывающим индикатором и помогает определить тренд. Она рисуется наложением поверх графика цен и первые значения обычно обычно отбрасываются. Обычно рассматривают пару идникаторов и точка, когда идикатор с коротким окном пересекает идикатор с длинным окном снизу рассматривается как потенциальная точка входа, и сверху — выхода. На практике чаще используют экспоненциально взвешенную скользящую среднюю, применяя весовую оконную функцию, что бы уменьшить эффект запаздывания.
Среднеквадратичное отклонение (STDEV)
Если мы заменим в предыдущем варианте функцию mean () на корень из дисперсии sd (), то получим уже скользящее среднеквадратичное отклонение.
function stdev($close, window) {
return rolling(x => sd(x), window, $close);
}
Дисперсия считается обычным всем известным способом, чаще всего без коррекции Бесселя. Так же чаще используется именно корень из дисперсии, так как сама дисперсия измеряется в квадратных рублях/долларах.
Полосы Боллинджера (BB)
Таким образом мы уже получили два базовых индикатора, которые уже можно комбинировать и получать новые. Например, если поточечно сложить скользящую среднюю и среднеквадратичное отклонение, при этом домножив на 2, то мы получим верхнюю часть полосы Боллинджера, а если вычесть — нижнюю.
В коде это будет выглядеть так
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 последних цен закрытия, можно понять что складывать можно с каким то весом, уменьшая вклад старых цен. Таким образом мы приходим к формуле взвешенной оконной функции.
$$display$$\frac{\sum x_i}{N} \Rightarrow \frac{\sum 1 \cdot x_i}{\sum 1} \Rightarrow \frac{\sum w_i x_i}{\sum w_i}$$display$$
если $inline$w_i=q^i$inline$ и выбрать какую то константу $inline$q$inline$ меньше единицы, то мы получим бесконечно убывающий вес, если при этом складывать цены начиная с самой новой.
Так строго высчитается взвешенная скользящая средняя. Но в продвинутых торговых системах существует два типа расчета ema. Так как можно значительно упростить вычисления, если не учитывать вклад хвостов. Расширив размер окна на всю длину и переобозначив константу, можно заметить, что следующий член рекуррентно выводится через предыдущий.
$$display$$ ema_i = close \cdot c + ema_{i-1} \cdot (1-c) \cdot$$display$$
при этом константу обычно выбирают равной $inline$c = 2 / (window + 1)$inline$, а за начальный отсчет выбирают среднее значение.
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;
}
В целом эта та же скользящая средняя, но более чувствительная. Эффективность использования зависит от вашего опыта и используемых настроек. Например на данном сайте довольно удачно подобраны параметры.
Cхождение/расхождение скользящих средних (MACD)
Джеральд Аппель в 1979 году придумал один из самых простых и в то же время эффективных осцилляторов ценовых моментов. Он преобразует два трендовых индикатора EMA в индикатор моментов, беря из двух миров лучшее. То есть он, грубо говоря, находит производную. Рисуется он в отдельном окне двумя линиями и гистограммой, а не наложением, как предыдущие. На самом деле индикаторов которые рисуются в отдельном окне значительно больше, но об этом может быть как нибудь в другой раз.
Формула расчета довольно простая, берутся две 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 };
}
Тестирование индикаторов, нормированная среднеквадратичная ошибка
Имея точные таблицы со значением индикаторов, можно качественно протестировать ваш расчет. Существую различные способы определения меры ошибки между двумя функциями, но практика показала что нормированная среднеквадратичная ошибка, которая считается как
$$display$$\mathrm{NRMSE} = \left. \sqrt{\frac{\sum (\hat x_i — x_i)^2} {N}} \middle/ (\max{x_i} — \min{x_i}) \right.$$display$$
лучше всего работает, как при малых величинах, так и при больших. Например биткоин в долларах может стоить 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. Tradingview — создание скриншотов, платформа с множеством индикаторов
4. Github — исходный код