Создание мощной стратегии на основе SuperTrend и RSI.
Индикаторы RSI и SuperTrend являются одними из самых мощных технических инструментов, которые у нас есть, поэтому их объединение может быть прибыльным. В этой статье обсуждается одна общая стратегия, основанная на двух индикаторах.
Я только что опубликовал новую книгу после успеха моей предыдущей «Новые технические индикаторы на Python». Он содержит более полное описание и добавление структурированных торговых стратегий со страницей GitHub, посвященной постоянно обновляемому коду. Если вы считаете, что это вас заинтересует, перейдите по ссылке ниже или, если вы предпочитаете купить версию в формате PDF, вы можете связаться со мной через LinkedIn.
RSI
RSI, без сомнения, является самым известным индикатором импульса, и этого следовало ожидать, поскольку у него много сильных сторон, особенно на ранжированных рынках. Он также ограничен диапазоном от 0 до 100, что упрощает интерпретацию. Кроме того, тот факт, что он известен, увеличивает его потенциал.
Это связано с тем, что чем больше трейдеров и управляющих портфелем будут смотреть на RSI, тем больше людей будет реагировать на его сигналы, а это, в свою очередь, может подтолкнуть рыночные цены. Конечно, мы не можем доказать эту идею, но она интуитивно понятна, поскольку одна из основ технического анализа заключается в том, что она самореализируется.
RSI рассчитывается довольно простым способом. Сначала мы берем разницу в ценах за один период. Это означает, что мы должны вычесть каждую цену закрытия из предыдущей. Затем мы вычислим сглаженное среднее положительных разностей и разделим его на сглаженное среднее отрицательных разностей. Последний расчет дает нам относительную силу, которая затем используется в формуле RSI для преобразования в меру от 0 до 100.
Для расчета индекса относительной силы нам понадобится массив OHLC (а не фрейм данных). Это означает, что мы будем смотреть на массив из 4 столбцов. Таким образом, функция индекса относительной силы:
def adder(Data, times): for i in range(1, times + 1): new = np.zeros((len(Data), 1), dtype = float) Data = np.append(Data, new, axis = 1) return Data def deleter(Data, index, times): for i in range(1, times + 1): Data = np.delete(Data, index, axis = 1) return Data def jump(Data, jump): Data = Data[jump:, ] return Data def ma(Data, lookback, close, where): Data = adder(Data, 1) for i in range(len(Data)): try: Data[i, where] = (Data[i - lookback + 1:i + 1, close].mean()) except IndexError: pass # Cleaning Data = jump(Data, lookback) return Data def ema(Data, alpha, lookback, what, where): alpha = alpha / (lookback + 1.0) beta = 1 - alpha # First value is a simple SMA Data = ma(Data, lookback, what, where) # Calculating first EMA Data[lookback + 1, where] = (Data[lookback + 1, what] * alpha) + (Data[lookback, where] * beta) # Calculating the rest of EMA for i in range(lookback + 2, len(Data)): try: Data[i, where] = (Data[i, what] * alpha) + (Data[i - 1, where] * beta) except IndexError: pass return Data def rsi(Data, lookback, close, where, width = 1, genre = 'Smoothed'): # Adding a few columns Data = adder(Data, 7) # Calculating Differences for i in range(len(Data)): Data[i, where] = Data[i, close] - Data[i - width, close] # Calculating the Up and Down absolute values for i in range(len(Data)): if Data[i, where] > 0: Data[i, where + 1] = Data[i, where] elif Data[i, where] < 0: Data[i, where + 2] = abs(Data[i, where]) # Calculating the Smoothed Moving Average on Up and Down absolute values if genre == 'Smoothed': lookback = (lookback * 2) - 1 # From exponential to smoothed Data = ema(Data, 2, lookback, where + 1, where + 3) Data = ema(Data, 2, lookback, where + 2, where + 4) if genre == 'Simple': Data = ma(Data, lookback, where + 1, where + 3) Data = ma(Data, lookback, where + 2, where + 4) # Calculating the Relative Strength Data[:, where + 5] = Data[:, where + 3] / Data[:, where + 4] # Calculate the Relative Strength Index Data[:, where + 6] = (100 - (100 / (1 + Data[:, where + 5]))) # Cleaning Data = deleter(Data, where, 6) Data = jump(Data, lookback) return Data
Если вы хотите поддержать меня и статьи, которые я регулярно публикую, рассмотрите возможность подписки на мой информационный бюллетень (доступен бесплатный план) по приведенной ниже ссылке. Это поможет мне продолжать делиться своими исследованиями. Спасибо!
Индикатор SuperTrend
Первая концепция, которую мы должны понять перед созданием индикатора SuperTrend, - это волатильность. Иногда мы измеряем волатильность, используя средний истинный диапазон. Хотя ATR считается запаздывающим индикатором, он дает некоторое представление о том, где сейчас волатильность и где она была в последний период (день, неделя, месяц и т. Д.). Но перед этим мы должны понять, как рассчитывается Истинный диапазон (ATR - это просто среднее значение этого расчета).
Истинный диапазон - это просто наибольшее из трех ценовых различий:
- Высокая - Низкая
- | High - Предыдущее закрытие |
- | Предыдущее закрытие - минимум |
Как только мы получили максимум из трех вышеупомянутых, мы просто берем среднее значение n периодов истинных диапазонов, чтобы получить средний истинный диапазон. Как правило, поскольку в периоды паники и снижения цен мы видим, что волатильность растет, ATR, скорее всего, будет иметь тенденцию к повышению в эти периоды, аналогично во время устойчивых восходящих или нисходящих тенденций ATR будет иметь тенденцию снижаться.
Всегда следует помнить, что этот индикатор запаздывает, и поэтому его нужно использовать с особой осторожностью. Ниже приведен код функции, вычисляющей ATR. Убедитесь, что у вас есть массив исторических данных OHLC.
def adder(Data, times): for i in range(1, times + 1): new = np.zeros((len(Data), 1), dtype = float) Data = np.append(Data, new, axis = 1) return Data def deleter(Data, index, times): for i in range(1, times + 1): Data = np.delete(Data, index, axis = 1) return Data def jump(Data, jump): Data = Data[jump:, ] return Data def ma(Data, lookback, close, where): Data = adder(Data, 1) for i in range(len(Data)): try: Data[i, where] = (Data[i - lookback + 1:i + 1, close].mean()) except IndexError: pass # Cleaning Data = jump(Data, lookback) return Data def ema(Data, alpha, lookback, what, where): alpha = alpha / (lookback + 1.0) beta = 1 - alpha # First value is a simple SMA Data = ma(Data, lookback, what, where) # Calculating first EMA Data[lookback + 1, where] = (Data[lookback + 1, what] * alpha) + (Data[lookback, where] * beta) # Calculating the rest of EMA for i in range(lookback + 2, len(Data)): try: Data[i, where] = (Data[i, what] * alpha) + (Data[i - 1, where] * beta) except IndexError: pass return Data def atr(Data, lookback, high, low, close, where, genre = 'Smoothed'): # Adding the required columns Data = adder(Data, 1) # True Range Calculation for i in range(len(Data)): try: Data[i, where] = max(Data[i, high] - Data[i, low], abs(Data[i, high] - Data[i - 1, close]), abs(Data[i, low] - Data[i - 1, close])) except ValueError: pass Data[0, where] = 0 if genre == 'Smoothed': # Average True Range Calculation Data = ema(Data, 2, lookback, where, where + 1) if genre == 'Simple': # Average True Range Calculation Data = ma(Data, lookback, where, where + 1) # Cleaning Data = deleter(Data, where, 1) Data = jump(Data, lookback) return Data
Теперь, когда мы поняли, что такое ATR и как его рассчитать, мы можем продолжить работу с индикатором SuperTrend. Индикатор стремится предоставить уровни входа и выхода для последователей тренда. Вы можете думать об этом как о скользящей средней или MACD. Его уникальность - это его главное преимущество, и хотя метод расчета намного сложнее, чем два других индикатора, он интуитивно понятен и не так сложен для понимания. По сути, у нас есть две переменные на выбор.
Обратный прогноз ATR и значение множителя. Первый - это просто период, используемый для расчета ATR, в то время как последний обычно является целым числом (обычно 2 или 3).
Первое, что нужно сделать, это усреднить максимум и минимум ценового бара, затем мы либо добавим, либо вычтем среднее значение с выбранным множителем, умноженным на ATR, как показано в приведенных выше формулах. Это даст нам два массива, базовую верхнюю полосу и базовую нижнюю полосу, которые образуют первые строительные блоки в индикаторе SuperTrend. Следующим шагом является вычисление окончательной верхней полосы и последней нижней полосы с использованием приведенных ниже формул.
Это может показаться сложным, но большинство этих условий повторяются, и в любом случае я предоставлю код Python ниже, чтобы вы могли поиграть с функцией и оптимизировать ее в соответствии со своими торговыми предпочтениями. Наконец, используя предыдущие два вычисления, мы можем найти SuperTrend.
def supertrend(Data, multiplier, atr_col, close, high, low, where): Data = adder(Data, 6) for i in range(len(Data)): # Average Price Data[i, where] = (Data[i, high] + Data[i, low]) / 2 # Basic Upper Band Data[i, where + 1] = Data[i, where] + (multiplier * Data[i, atr_col]) # Lower Upper Band Data[i, where + 2] = Data[i, where] - (multiplier * Data[i, atr_col]) # Final Upper Band for i in range(len(Data)): if i == 0: Data[i, where + 3] = 0 else: if (Data[i, where + 1] < Data[i - 1, where + 3]) or (Data[i - 1, close] > Data[i - 1, where + 3]): Data[i, where + 3] = Data[i, where + 1] else: Data[i, where + 3] = Data[i - 1, where + 3] # Final Lower Band for i in range(len(Data)): if i == 0: Data[i, where + 4] = 0 else: if (Data[i, where + 2] > Data[i - 1, where + 4]) or (Data[i - 1, close] < Data[i - 1, where + 4]): Data[i, where + 4] = Data[i, where + 2] else: Data[i, where + 4] = Data[i - 1, where + 4] # SuperTrend for i in range(len(Data)): if i == 0: Data[i, where + 5] = 0 elif (Data[i - 1, where + 5] == Data[i - 1, where + 3]) and (Data[i, close] <= Data[i, where + 3]): Data[i, where + 5] = Data[i, where + 3] elif (Data[i - 1, where + 5] == Data[i - 1, where + 3]) and (Data[i, close] > Data[i, where + 3]): Data[i, where + 5] = Data[i, where + 4] elif (Data[i - 1, where + 5] == Data[i - 1, where + 4]) and (Data[i, close] >= Data[i, where + 4]): Data[i, where + 5] = Data[i, where + 4] elif (Data[i - 1, where + 5] == Data[i - 1, where + 4]) and (Data[i, close] < Data[i, where + 4]): Data[i, where + 5] = Data[i, where + 3] # Cleaning columns Data = deleter(Data, where, 5) return Data
На приведенном выше графике показаны почасовые значения EURUSD с 10-периодным супертрендом (представлен периодом ATR) и множителем 1,25.
Мы должны понимать индикатор так, что, когда он поднимается выше рыночной цены, мы должны открывать короткую позицию, а когда он опускается ниже рыночной цены, мы должны стремиться открывать длинную позицию, поскольку мы ожидаем бычьего тренда. Помните, что SuperTrend - это индикатор, следующий за трендом. Цель здесь - уловить тенденции в начале и закрыть, когда они закончатся.
Если вас также интересуют другие технические индикаторы и использование Python для создания стратегий, то мой бестселлер по техническим индикаторам может вас заинтересовать:
Создание и оценка стратегии
Теперь наша задача - создать массив, содержащий данные OHLC, а также столбцы для RSI и SuperTrend. Мы можем сделать это, следуя этому коду, если мы импортировали необходимые исторические данные.
# Indicator Parameters lookback_rsi = 13 lookback_supertrend = 10 multiplier = 3 # Adding a few columns my_data = adder(my_data, 10) # Calling the RSI function my_data = rsi(my_data, lookback_rsi, 3, 4) # Calling the ATR function to be used in the SuperTrend my_data = atr(my_data, lookback_supertrend, 1, 2, 3, 5, genre = 'Smoothed') # Calling the SuperTrend Indicator my_data = supertrend(my_data, multiplier, 5, 3, 1, 2, 6)
Стратегия основана на переходе от SuperTrend с условием, что RSI выше его уровня нейтральности 50%. Это усиливает бычий уклон и наоборот медвежий уклон.
- Сигнал на покупку (длинную позицию) генерируется всякий раз, когда индикатор SuperTrend опускается ниже рыночной цены, в то время как RSI превышает 50%.
- Сигнал на продажу (короткую продажу) генерируется всякий раз, когда индикатор SuperTrend поднимается выше рыночной цены, а RSI ниже 50%.
def signal(Data, close, rsi_column, supertrend_column, buy, sell): Data = adder(Data, 10) for i in range(len(Data)): if Data[i, rsi_column] > 50 and Data[i, close] > Data[i, supertrend_column] and Data[i - 1, close] < Data[i - 1, supertrend_column]: Data[i, buy] = 1 elif Data[i, rsi_column] < 50 and Data[i, close] < Data[i, supertrend_column] and Data[i - 1, close] > Data[i - 1, supertrend_column]: Data[i, sell] = -1 return Data
Стратегия в ее стандартной форме вряд ли предоставит ценные сигналы, и ее необходимо настроить так, чтобы она улавливала лучшие сигналы. Возможно, дальнейшие исследования покажут лучшие сигналы?
Заключение
Не забывайте всегда проводить тесты на исторических данных. Вы всегда должны верить, что другие люди неправы. Мои индикаторы и стиль торговли могут работать на меня, но может не на вас.
Я твердо убежден, что нельзя кормить с ложечки. Я научился на практике, а не копируя. Вы должны понять идею, функцию, интуицию, условия стратегии, а затем разработать (даже лучше) одну из них самостоятельно, чтобы вы протестировали и улучшили ее, прежде чем принимать решение о том, чтобы воплотить ее в жизнь или отказаться от нее. Мой выбор в пользу отказа от предоставления конкретных результатов тестирования на истории должен побудить читателя лучше изучить стратегию и больше работать над ней.
Подводя итог, можно ли сказать, что стратегии, которые я предлагаю, реалистичны? Да, но только путем оптимизации среды (надежный алгоритм, низкие затраты, честный брокер, надлежащее управление рисками и управление заказами). Предусмотрены ли стратегии исключительно для торговли? Нет, это нужно для стимулирования мозгового штурма и получения новых торговых идей, поскольку мы все устали слышать о перепроданности RSI как о причине для открытия короткой позиции или о преодолении сопротивления как о причине идти долго. Я пытаюсь представить новую область под названием «Объективный технический анализ», в которой мы используем достоверные данные для оценки наших методов, а не полагаемся на устаревшие классические методы.