Как устроены индикаторы. Часть 3: SMMA, EWMA, MMA, RMA, RSI, STOCH, STOCHRSI

Настало время разобраться с новыми индикаторами, сегодня ими выступят RSI, STOCH, STOCHRSI, а так же мы немного модифицируем скользящие средние, что бы получать SMMA, MMA и RMA. Последние нам понадобятся для построения первых. С них и начнем.

Добавляем SMMA, EWMA, MMA, RMA

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

Существует куча этих сглаживающих, но все они либо синонимы одной и той же, либо отличаются коэффициентом сглаживания. Например, EMA и EWMA – это одно и тоже, берется SMA и к ней применяется сглаживание по формуле 2/(period+1).

SMMA, MMA, RMA три названия одной и  той же сглаживающей, которая тоже самое, что EMA, но с коэффициентом сглаживания 1/period. Больше информации о скользящих можно получить тут.

Поэтому немного изменим наш код, создадим сущность generalEMA, которой на вход будем подавать параметры – массив цен, период и коэффициент, её будут вызывать «обычные» функции, такие как EMA и SMMA, что бы никто не путался.

Ссылку на код я дам ниже, пока несколько замечаний: как вы видите, мы только что добавили в библиотеку «несколько» новых индикаторов, каждый из которых вызывает EMA, под собственным именем, и коэффициенты зашиты внутри реализации, что бы не писать одно и тоже по 10 раз.

Если мне где-то, в какой то стратегии встретится, что нужно использовать MMA, то я не буду ничего изобретать, а просто использую MMA из свой библиотеки, и не буду помнить о том, что на самом деле MMA вызывает SMMA, а SMMA это в свою очередь обычная EMA, но с измененным коэффициентом сглаживания. Жаль, что не все, кто учит торговать по индикаторам, знают их особенности.

Еще замечание – функция generalEMA занимает 16 строк, не считая пробелов, функция SMA, которую она вызывает – 20 строк. В 36 строках кода – как минимум три уникальных скользящих. Я пишу это, не для того, чтобы подчеркнуть качество кода, а с целью указать на «интеллектуальность» этого класса индикаторов.

Вот результат вывода – вызвали каждую функцию, можно заметить, что у нужных функций одинаковые результаты:

Зачем мы всё это делаем? Нам нужна была функция RSI, а её создатель использовал SMMA. Давайте теперь сделаем RSI.


Реклама


Добавляем RSI

RSI позиционируется как индекс перекупленности/перепроданности. Он возвращает значения от 0 до 100, считается что значения ниже 30 говорят о недооценности рынка (пора покупать), а выше 70 – о перекупленности (не надо покупать, пора продавать).

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

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

Если дать на вход RSI сто цен закрытия, то он

  1. Создаст два массива длиной 100 – для восходящих (U) и нисходящих дней (D)
  2. Пробежится по указанным ценам, заполнит массивы – если день восходящий, он в массив U запишет значение (цена сегодня-цена вчера), в массив D – 0. Если день нисходящий, то в массив D запишет (цена вчера-цена сегодня), в массив U – 0. Если день никчемный, поставит и там и там нули.
  3. Оба массива по очереди скормит функции SMMA с переданным кол-вом периодов сглаживания. Т.е. если обычно мы вызывали SMMA, передавая ей closes и какой-то период (например 100), то теперь её вызывает функция RSI, передавая массив с нулями и разницами цен и период (7, 14, 21 как правило). Подробнее см. код ниже
  4. После того, как SMMA посчитает и вернет два массива значений, RSI по очереди будет брать по одному значению из каждого массива, делить одно на другое (это будет RS, относительная сила), и применять формулу 100-100/(1+RS). Результат будет добавляться в результирующий массив. Если в делителе 0 (был только рост), то подставляется просто 100.

Проще посмотреть код, на мой взгляд. Вот он (не уверен даже, стоит ли его комментировать):

def RSI(data, period):
    u_days = []
    d_days = []

    for i, _ in enumerate(data):
        if i == 0:
            u_days.append(0)
            d_days.append(0)
        else:
            if data[i] > data[i-1] :
                u_days.append(data[i] - data[i-1])
                d_days.append(0)
            elif data[i] < data[i-1]:
                d_days.append(data[i-1] - data[i])
                u_days.append(0)
            else:
                u_days.append(0)
                d_days.append(0)

    smma_u = SMMA(u_days, period)
    smma_d = SMMA(d_days, period)

    result = []

    for k, _ in enumerate(data):
        if smma_d[k] == 0:
            result.append(100)
        else:
            result.append(100 - (100 / (1 + smma_u[k]/smma_d[k])))

    return result

Гуд! Пойдем к стохастикам


Реклама


Добавляем STOCH

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

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

Подробнее можете почитать в википедии, там маленькая статья и есть несколько примеров. Вот как реализуется индикатор:

def STOCH(high, low, closes, fastk_period, slowk_period, slowd_period):
    fastk = []
    
    for i, _ in enumerate(closes):
        if (i + 1) < fastk_period:
            fastk.append(math.nan)
        else:
            lower_bound = i + 1 - fastk_period
            upper_bound = i + 1
            curr_low = min(low[lower_bound:upper_bound])
            curr_high = max(high[lower_bound:upper_bound])
            fastk.append(((closes[i] - curr_low) / (curr_high - curr_low)) * 100)
       
    fastk = EMA(fastk, slowk_period)
    slowd = EMA(fastk, slowd_period)

    return fastk, slowd

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

STOCHRSI

Тут вообще всё просто. Взяли RSI и посчитали его значения с помощью стохастика. Вот так:

def STOCHRSI(data, period, fastk_period, fastd_period):
    rsi = RSI(data, period)
    return STOCH(rsi, rsi, rsi, period, fastk_period, fastd_period)

Вроде как он взял лучшее от двух индикаторов, и еще лучше всё считает. Им многие пользуются, но решать конечно вам.


Реклама


Достаточно!

В рамках одной статьи уже достаточно материала, в следующий раз рассмотрим D2 (DEMA), T3(TEMA) и линии Боллинджера.

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

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

Удачи!


Это статья из цикла "Теханализ + Разработка индикаторов"
Все статьи цикла:

Последнее изменение:

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



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

Bitcoin адрес проекта: [[address]]

Перевод на сумму [[value]] BTC получен. Спасибо!.
[[error]]

Ethereum адрес проекта: [[address]]