Настало время разобраться с новыми индикаторами, сегодня ими выступят 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 сто цен закрытия, то он
- Создаст два массива длиной 100 – для восходящих (U) и нисходящих дней (D)
- Пробежится по указанным ценам, заполнит массивы – если день восходящий, он в массив U запишет значение (цена сегодня-цена вчера), в массив D – 0. Если день нисходящий, то в массив D запишет (цена вчера-цена сегодня), в массив U – 0. Если день никчемный, поставит и там и там нули.
- Оба массива по очереди скормит функции SMMA с переданным кол-вом периодов сглаживания. Т.е. если обычно мы вызывали SMMA, передавая ей closes и какой-то период (например 100), то теперь её вызывает функция RSI, передавая массив с нулями и разницами цен и период (7, 14, 21 как правило). Подробнее см. код ниже
- После того, как 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) и линии Боллинджера.
Я надеюсь, что смог добавить крупицу знаний в вашу копилку, или дать повод для размышления.
Весь код, указанный в статье, вы можете найти тут и пользоваться, как вам угодно. Если что, там есть рядом такая же библиотека для голанга, там покрытие тестами и прочие радости. Велкам, если желаете поучаствовать.
Удачи!