Кодирование известной торговой стратегии на Python.

Технические стратегии есть во всем Интернете. 99,99% из них не работают или работают всего несколько недель. К сожалению, рынки постоянно меняются, и большинство стратегий устаревают. Даже стратегии, которые я использовал в прошлом, были изменены, чтобы соответствовать текущим условиям. В этой статье обсуждается и тестируется известная стратегия, найденная в Интернете, которая использует RSI и стохастический осциллятор.

Я только что выпустил новую книгу после успеха предыдущей книги. Он содержит расширенные индикаторы и стратегии следования за трендом, а также страницу GitHub, посвященную постоянно обновляемому коду. Кроме того, в этой книге представлены оригинальные цвета после оптимизации затрат на печать. Если вы чувствуете, что это вас интересует, не стесняйтесь посетить приведенную ниже ссылку Amazon, или, если вы предпочитаете купить версию в формате PDF, вы можете связаться со мной на LinkedIn.



Стохастический осциллятор

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

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

def stochastic_oscillator(data, 
                             lookback, 
                             high, 
                             low, 
                             close, 
                             where, 
                             slowing = False, 
                             smoothing = False, 
                             slowing_period = 1, 
                             smoothing_period = 1):
            
    data = adder(data, 1)
        
    for i in range(len(data)):
            
        try:
            
            data[i, where] = (data[i, close] - min(data[i - lookback + 1:i + 1, low])) / (max(data[i - lookback + 1:i + 1, high]) - min(data[i - lookback + 1:i + 1, low]))
            
        except ValueError:
            
            pass
        
    data[:, where] = data[:, where] * 100  
            
    if slowing == True and smoothing == False:
        
        data = ma(data, slowing_period, where, where + 1)
    
    if smoothing == True and slowing == False:
        
        data = ma(data, smoothing_period, where, where + 1)
        
    if smoothing == True and slowing == True:
    
        data = ma(data, slowing_period, where,   where + 1)
        
        data = ma(data, smoothing_period, where, where + 2)        
       
    data = jump(data, lookback)    
    return data



Индекс относительной силы

Впервые представленный Дж. Уэллсом Уайлдером-младшим, RSI является одним из самых популярных и универсальных технических индикаторов. В основном используется как противоположный индикатор, где экстремальные значения сигнализируют о реакции, которую можно использовать. Как правило, мы используем следующие шаги для расчета RSI по умолчанию:

  • Рассчитайте изменение цен закрытия по сравнению с предыдущими.
  • Отделите положительные чистые изменения от отрицательных чистых изменений.
  • Вычислите сглаженное скользящее среднее положительных чистых изменений и абсолютных значений отрицательных чистых изменений.
  • Разделите сглаженные положительные изменения на сглаженные отрицательные изменения. Мы будем называть этот расчет Относительной Силой — RS.
  • Примените формулу нормализации, показанную ниже, для каждого временного шага, чтобы получить RSI.

На приведенном выше графике часовые значения GBPUSD показаны черным цветом с 13-периодным RSI. В целом мы можем отметить, что RSI имеет тенденцию отскакивать близко к 25, в то время как он имеет тенденцию останавливаться около 75. Чтобы закодировать RSI в Python, нам нужен массив 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
            
    data = jump(data, lookback)
    
    return data
def ema(data, alpha, lookback, what, where):
    
    alpha = alpha / (lookback + 1.0)
    
    beta  = 1 - alpha
    
    data = ma(data, lookback, what, where)
    data[lookback + 1, where] = (data[lookback + 1, what] * alpha) + (data[lookback, where] * beta)
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):
    
    data = adder(data, 5)
    
    for i in range(len(data)):
        
        data[i, where] = data[i, close] - data[i - 1, close]
     
    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])
            
    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)
    data[:, where + 5] = data[:, where + 3] / data[:, where + 4]
    
    data[:, where + 6] = (100 - (100 / (1 + data[:, where + 5])))
    data = deleter(data, where, 6)
    data = jump(data, lookback)
    return data

Если вас также интересуют более технические индикаторы и стратегии, то моя книга может вас заинтересовать:



Создание и обратное тестирование стратегии

Стратегия состоит из трех индикаторов:

  • Индекс относительной силы за 14 периодов.
  • 14-периодный стохастический осциллятор с замедлением и сглаживанием на уровне 5.
  • Экспоненциальная скользящая средняя с периодом 200.

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

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

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

def ema(data, alpha, lookback, what, where):
    
    alpha = alpha / (lookback + 1.0)
    
    beta  = 1 - alpha
    
    data = ma(data, lookback, what, where)
    data[lookback + 1, where] = (data[lookback + 1, what] * alpha) + (data[lookback, where] * beta)
    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

Условия стратегии следующие:

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

Что такое скрытая дивергенция? Естественно, когда цены растут и формируют новые вершины, в то время как основанный на цене индикатор формирует более низкие вершины, происходит ослабление, и может появиться возможность изменить уклон с длинной позиции на короткую. Это то, что мы называем нормальной дивергенцией. Мы знаем это:

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

Скрытое расхождение можно рассматривать как зеркальное отражение нормального расхождения. Вот как:

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

А что такое положительный и отрицательный крест? Всякий раз, когда стохастический осциллятор превосходит свою 5-периодную скользящую среднюю, происходит положительное пересечение, что является бычьим сигналом, и всякий раз, когда стохастический осциллятор пробивает свою 5-периодную скользящую среднюю, происходит отрицательное пересечение, что является медвежьим сигналом.

Ниже приведен код сигналов стратегии.

def hidden_divergence(data, close, rsi_col, width, buy, sell):
    
    data = adder(data, 10)
    for i in range(len(data)):
        
        try:
            if data[i, rsi_col] < 50 and data[i - 1, rsi_col] > 50:
                
                for a in range(i + 1, i + width):
                    
                    if data[a, rsi_col] > 50:
                        
                        for r in range(a + 1, a + width):
                            
                            if data[r, rsi_col] < 50 and \
                            data[r, rsi_col] < data[i, rsi_col] and data[r, close] > data[i, close]:
                                
                                data[r, buy] = 1
                                break
else:
                            break
                    else:
                        break
                    
        except IndexError:
            pass
        
    for i in range(len(data)):
        
        try:
            if data[i, rsi_col] > 50 and data[i - 1, rsi_col] < 50:
                
                for a in range(i + 1, i + width):
                    
                    if data[a, rsi_col] < 50:
                        
                        for r in range(a + 1, a + width):
                            
                            if data[r, rsi_col] > 50 and \
                            data[r, rsi_col] > data[i, rsi_col] and data[r, close] < data[i, close]:
                                
                                data[r, sell] = -1     
                                break
else:
                            break
                    else:
                        break
                    
        except IndexError:
            pass 
        
    return data
my_data = hidden_divergence(my_data, 3, 5, 60, 8, 9)
for i in range(len(my_data)):
    
    if my_data[i, 8] == 1:
        
        for a in range(i + 1, i + 50):
            try:
            
                if my_data[a, 6] > my_data[a, 7] and my_data[a - 1, 6] < my_data[a - 1, 7] and my_data[a, 3] > my_data[a, 4]:
                    
                    my_data[a, 10] = 1
                    break
except IndexError:
                pass
            
    if my_data[i, 9] == -1:
        
        for a in range(i + 1, i + 50):
            try:
                
                if my_data[a, 6] < my_data[a, 7] and my_data[a - 1, 6] > my_data[a - 1, 7] and my_data[a, 3] < my_data[a, 4]:
                    
                    my_data[a, 11] = -1
                    break
except IndexError:
                pass

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

И, наконец, давайте протестируем эту стратегию, используя простые условия:

  • Отсутствие управления рисками. Мы будем открывать и закрывать на основе следующего сигнала.
  • Проверенный актив — USDJPY.
  • Купля-продажа близка к завершению.

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

Если вы хотите получать больше статей о торговых стратегиях, рассмотрите возможность подписки на мой ЕЖЕДНЕВНЫЙ информационный бюллетень (доступен бесплатныйплан) по ссылке ниже. В нем представлены мои статьи на Medium, другие торговые стратегии, уроки кодирования, связанные с исследованиями и анализом, а также подписчики получают бесплатную копию моей первой книги в формате PDF. Вы можете ожидать 5–7 статей в неделю с платной подпиской и 1–2 статей в неделю с бесплатным планом. Это помогло бы мне продолжить делиться своими исследованиями. Спасибо!



Не забывайте всегда проводить бэк-тесты. Вы всегда должны верить, что другие люди неправы. Мои индикаторы и стиль торговли могут подойти мне, но не вам.

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

Последнее слово

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

  • Высокая потенциальная выгода: концентрируя оставшиеся средства от продаж на маркетинге и продвижении Общества Света, я стремлюсь максимально увеличить их ценность на вторичном рынке. рынок. Помните, что торговля на вторичном рынке также означает, что часть роялти будет передана той же благотворительной организации.
  • Коллекция произведений искусства и диверсификация портфолио. Иметь коллекцию аватаров, символизирующих добрые дела, очень приятно. Инвестирование не обязательно должно быть связано только с эгоистичными потребностями, хотя нет ничего плохого в том, чтобы инвестировать, чтобы заработать деньги. Но как насчет того, чтобы инвестировать, зарабатывая деньги, помогая другим и собирая произведения искусства?
  • Пожертвования на предпочитаемые цели. Это гибкий способ выделения различных средств на ваши благотворительные цели.
  • Бесплатная копия моей книги в формате PDF: любой покупатель любого NFT получит бесплатную копию моей последней книги, указанной в ссылке на статью.