Создание и построение стохастического индикатора Боллинджера с использованием Python.

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

Я только что опубликовал новую книгу после успеха предыдущей книги под названием «Новые технические индикаторы в Python». В новой книге представлено более полное описание и добавление стратегий со страницей Github, посвященной коду (которая постоянно заполняется и обновляется). Если вы чувствуете, что это вас заинтересует, не сомневайтесь, также можно приобрести PDF-версию, вы можете связаться со мной в Linkedin.



Концепция нормализации

Этот замечательный метод позволяет нам улавливать значения от 0 до 1 (или от 0 до 100, если мы хотим умножить на 100). Концепция вращается вокруг вычитания минимального значения в определенном периоде ретроспективного анализа из текущего значения и деления на максимальное значение в тот же период ретроспективного анализа за вычетом минимального значения (то же самое в номинаторе).

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

# The function to add a certain number of columns
def adder(Data, times):
    
    for i in range(1, times + 1):
    
        z = np.zeros((len(Data), 1), dtype = float)
        Data = np.append(Data, z, axis = 1)
    return Data
# The function to deleter a certain number of columns
def deleter(Data, index, times):
    
    for i in range(1, times + 1):
    
        Data = np.delete(Data, index, axis = 1)               
    
    return Data
# The function to delete a certain number of rows from the beginning
def jump(Data, jump):
    
    Data = Data[jump:, ]
    
    return Data

Мы можем попробовать кодировать функцию нормализации на питоне. Ниже приводится нормализация данного временного ряда:

def normalizer(Data, lookback, what, where):
        
    for i in range(len(Data)):
        
        try:
            Data[i, where] = (Data[i, what] - min(Data[i - lookback + 1:i + 1, what])) / (max(Data[i - lookback + 1:i + 1, what]) - min(Data[i - lookback + 1:i + 1, what]))
        
        except ValueError:
            pass
    
    Data[:, where] = Data[:, where] * 100    
    Data = jump(Data, lookback)
    return Data

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

# Using the function
my_data = normalizer(my_data, 50, 3, 4)

Пошаговое создание стохастического осциллятора

Осциллятор стохастик пытается найти зоны перепроданности и перекупленности, объединяя максимумы и минимумы, используя формулу нормализации, как показано ниже:

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

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

def stochastic(Data, lookback, what, high, low, where):
        
    for i in range(len(Data)):
        
        try:
          Data[i, where] = (Data[i, what] - 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                     
    return Data
# The Data variable refers to the OHLC array
# The lookback variable refers to the period (5, 14, 21, etc.)
# The what variable refers to the closing price
# The high variable refers to the high price
# The low variable refers to the low price
# The where variable refers to where to put the Oscillator

На приведенном выше графике показаны значения EURUSD с помощью 14-периодного стохастического осциллятора. Обратите внимание, что индикатор всегда будет ограничен между 0 и 100 из-за характера его функции нормализации, которая улавливает значения между минимумом и максимумом.

Полосы Боллинджера

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

Предположим, что это своевременно упорядоченный временной ряд. Если бы нам пришлось наивно угадывать следующее значение после 10, то одним из лучших предположений может быть среднее значение данных. Следовательно, если мы просуммируем значения {5, 10, 15, 5, 10} и разделим их на их количество (т.е. 5), мы получим 9. Это среднее значение для указанного выше набора данных. В python мы можем сгенерировать список или массив, а затем легко вычислить среднее значение:

# Importing the required library
import numpy as np
# Creating the array
array = [5, 10, 15, 5, 10]
array = np.array(array)
# Calculating the mean
array.mean()

Теперь, когда мы вычислили среднее значение, мы видим, что никакое значение в наборе данных на самом деле не равно 9. Как мы узнаем, что набор данных обычно не близок к набору данных? Это измеряется тем, что мы называем стандартным отклонением (волатильностью).

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

# Calculating the mean
array.std()

Приведенный выше фрагмент кода вычисляет стандартное отклонение набора данных, которое составляет около 3,74. Это означает, что в среднем отдельные значения отличаются от 9 (среднего) на 3,74 единицы. Теперь перейдем к нормальному распределению, показанному на кривой ниже.

Кривая выше показывает количество значений в пределах ряда стандартных отклонений. Например, область, заштрихованная красным, соответствует примерно 1,33-кратному стандартному отклонению от нулевого среднего значения. Мы знаем, что при нормальном распределении данных:

  • Около 68% данных находится в пределах 1 стандартного отклонения от среднего.
  • Около 95% данных находится в пределах 2 стандартных отклонений от среднего.
  • Около 99% данных находится в пределах 3 стандартных отклонений от среднего.

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

Теперь, с информацией ниже, мы готовы приступить к созданию индикатора Bollinger Bands:

  • Данные финансовых временных рядов могут иметь скользящее среднее, которое вычисляет окно скользящего среднего. Например, 20-периодное скользящее среднее вычисляется каждый раз, когда 20-периодное среднее значение обновляется каждый раз, когда формируется новый столбец.
  • В этом окне скользящего среднего мы можем рассчитать стандартное отклонение скользящего среднего за тот же период ретроспективного анализа.

Что такое полосы Боллинджера? Когда цены движутся, мы можем вычислить вокруг них скользящую среднюю (среднее), чтобы лучше понять их позицию относительно их среднего значения. Делая это, мы также можем подсчитать, где они находятся статистически.

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

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

Для расчета двух полос мы используем следующие относительно простые формулы:

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

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

Чтобы создать полосы Боллинджера в Python, нам нужно определить функцию скользящего среднего, функцию стандартного отклонения, а затем функцию полос Боллинджера, которая будет использовать первые две функции.

Теперь нам нужно добавить несколько столбцов в массив OHLC, определить скользящую среднюю и функции Боллинджера, а затем, наконец, использовать их.

# Adding a few columns
Data = adder(Data, 20)
def ma(Data, lookback, what, where):
    
    for i in range(len(Data)):
      try:
        Data[i, where] = (Data[i - lookback + 1:i + 1, what].mean())
        
            except IndexError:
                pass
    return Data
def volatility(Data, lookback, what, where):
    
    for i in range(len(Data)):
      try:
        Data[i, where] = (Data[i - lookback + 1:i + 1, what].std())
    
        except IndexError:
            pass
        
    return Data
def BollingerBands(Data, boll_lookback, standard_distance, what, where):
       
    # Calculating mean 
    ma(Data, boll_lookback, what, where)                           
    # Calculating volatility
    volatility(Data, boll_lookback, what, where + 1)
    
    Data[:, where + 2] = Data[:, where] + (standard_distance *  Data[:, where + 1])
    Data[:, where + 3] = Data[:, where] - (standard_distance * Data[:, where + 1])
        
    return Data
# Using the function to calculate a 20-period Bollinger Band with 2 Standard Deviations
Data = BollingerBands(Data, 20, 2, 3, 4)

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



Стохастик Боллинджера

Идея индикатора заключается в применении полос Боллинджера к значениям стохастического осциллятора, тем самым формируя конверт и устраняя необходимость в верхних и нижних барьерах в качестве прокси-серверов поддержки / сопротивления. Это может быть особенно полезно для долгосрочных стохастических осцилляторов, поскольку они менее изменчивы, чем 2-периодные или 10-периодные осцилляторы.

Параметры Bollinger Stochastic по умолчанию будут следующими:

  • Стохастический осциллятор с периодом 55, применяемый, как обычно, к ценам максимума, минимума и закрытия.
  • 10-периодные полосы Боллинджера, примененные к стохастическому осциллятору со стандартным отклонением 1,5.

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

  • Открывайте длинную позицию (покупайте) всякий раз, когда 55-периодный стохастический осциллятор касается или превышает верхнюю полосу 10-периодного индикатора Боллинджера.
  • Открывайте короткую позицию (продавайте) всякий раз, когда 55-периодный стохастический осциллятор касается или пробивает нижнюю полосу 10-периодного индикатора Боллинджера.

Чтобы создать индикатор, мы можем использовать этот код:

boll_lookback       = 10
standard_deviation  = 1.5
stochastic_lookback = 55
my_data = stochastic(my_data, rsi_lookback, 3, 4, genre = 'High-Low')
my_data = BollingerBands(my_data, boll_lookback, standard_deviation, 4, 5)

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

Указанный выше сигнальный индикатор создается по этим двум формулам:

  • Если осциллятор стохастик находится выше верхней полосы Боллинджера, то текущее значение сигнального индикатора равно 1.
  • Если осциллятор стохастик ниже нижней полосы Боллинджера, текущее значение сигнального индикатора равно -1.
for i in range(len(my_data)):
    
    if my_data[i, 5] - my_data[i, 4] < 0:
        
        my_data[i, 9] = 1
elif my_data[i, 4] - my_data[i, 6] < 0:
        
        my_data[i, 9] = -1

Возвращаемся к штатной версии индикатора. Стратегия хорошо работает в сочетании с правильным управлением рисками на основе показателей волатильности. Ниже показан график сигналов по паре EURUSD.

def signal(Data, stochastic_column, upper_boll, lower_boll, buy, sell):
    
    Data = adder(Data, 10)
    
    for i in range(len(Data)):
        if Data[i, stochastic_column] < Data[i, lower_boll] and Data[i - 1, stochastic_column] > Data[i - 1, lower_boll]:
               Data[i, buy] = 1
               
        elif Data[i, stochastic_column] > Data[i, upper_boll] and Data[i - 1, stochastic_column] < Data[i - 1, upper_boll]:
            Data[i, sell] = -1   
            
    return Data

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

Фреймворк бэк-тестирования

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

В приведенной выше таблице говорится, что нам нужен индикатор или генератор сигналов в столбце 4 или 5 (помните, индексирование в Python начинается с нуля). Сигнал покупки (константа = 1) в столбце с индексом 6 и сигнал короткой продажи (константа = -1) в столбце с индексом 7. Это гарантирует, что оставшаяся часть приведенного ниже кода работает так, как должна работать. Причина этого в том, что в данных OHLC у нас уже заняты первые 4 столбца, поэтому нам остается 1 или 2 столбца для размещения наших индикаторов, прежде чем появятся два столбца сигналов. Использование функции удаления, показанной выше, может помочь вам достичь этого порядка, если индикаторы занимают более 2 столбцов.

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

def holding(Data, buy, sell, buy_return, sell_return):for i in range(len(Data)):
        try:
            if Data[i, buy] == 1: 
               for a in range(i + 1, i + 1000):                        
                  if Data[a, buy] != 0 or Data[a, sell] != 0:
                     Data[a, buy_return] = (Data[a, 3] - Data[i, 3])
                        break                        
                    else:
                        continue
                
            elif Data[i, sell] == -1:        
               for a in range(i + 1, i + 1000):                        
                  if Data[a, buy] != 0 or Data[a, sell] != 0:
                    Data[a, sell_return] = (Data[i, 3] - Data[a, 3])
                        break                                        
                    else:
                        continue                                         
        except IndexError:
            pass
# Using the function
holding(my_data, 6, 7, 8, 9)

Это даст нам столбцы 8 и 9, заполненные результатами валовых прибылей и убытков по заключенным сделкам. Теперь нам нужно преобразовать их в совокупные числа, чтобы рассчитать кривую собственного капитала. Для этого мы используем следующую функцию индексатора:

def indexer(Data, expected_cost, lot, investment):
    
    # Charting portfolio evolution  
    indexer = Data[:, 8:10]    
    
    # Creating a combined array for long and short returns
    z = np.zeros((len(Data), 1), dtype = float)
    indexer = np.append(indexer, z, axis = 1)
    
    # Combining Returns
    for i in range(len(indexer)):
        try:    
          if indexer[i, 0] != 0:
             indexer[i, 2] = indexer[i, 0] - (expected_cost / lot)
                
          if indexer[i, 1] != 0:
             indexer[i, 2] = indexer[i, 1] - (expected_cost / lot)
        except IndexError:
            pass
        
    # Switching to monetary values
    indexer[:, 2] = indexer[:, 2] * lot
    
    # Creating a portfolio balance array
    indexer = np.append(indexer, z, axis = 1)
    indexer[:, 3] = investment 
    
    # Adding returns to the balance    
    for i in range(len(indexer)):
    
        indexer[i, 3] = indexer[i - 1, 3] + (indexer[i, 2])
    
    indexer = np.array(indexer)
    
    return np.array(indexer)
# Using the function for a 0.1 lot strategy on $10,000 investment
expected_cost = 0.5 * (lot / 10000) # 0.5 pip spread
investment    = 10000                  
lot           = 10000
equity_curve = indexer(my_data, expected_cost, lot, investment)

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

plt.plot(equity_curve[:, 3], linewidth = 1, label = 'EURUSD)
plt.grid()
plt.legend()
plt.axhline(y = investment, color = 'black’, linewidth = 1)
plt.title(’Strategy’, fontsize = 20)

Теперь пора начать оценивать производительность с помощью других мер.

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

Hit ratio       =  42.28 % # Simulated Ratio

Коэффициент попадания чрезвычайно прост в использовании. Это просто количество прибыльных сделок по сравнению с общим количеством заключенных сделок. Например, если в течение 5 лет у нас было 1359 сделок и 711 из них были прибыльными, то наш коэффициент совпадения (точность) составляет 711/1359 = 52,31%.

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

Net profit      =  $ 1209.4 # Simulated Profit

Показатель чистой прибыли - это ваша прибыль на ваши инвестиции или собственный капитал. Если вы начали с 1000 долларов, а в конце года на вашем балансе будет 1300 долларов, то вы заработали бы здоровые 30%.

Net Return      =  30.01% # Simulated Return

Быстрый взгляд на среднюю прибыль по сделкам и средний убыток может помочь нам лучше управлять нашими рисками. Например, если наша средняя прибыль составляет 1,20 доллара, а средний убыток - 4,02 доллара, то мы знаем, что что-то не так, поскольку мы рискуем слишком большими деньгами в обмен на слишком маленькую прибыль.

Average Gain    =  $ 56.95 per trade # Simulated Average Gain
Average Loss    =  $ -41.14 per trade # Simulated Average Loss

После этого мы можем рассчитать две меры:

  • Теоретическое соотношение риска и прибыли: это желаемое отношение средней прибыли к средним потерям. Коэффициент 2,0 означает, что мы нацелены вдвое больше, чем рискуем.
  • Реализованное соотношение риска и прибыли: это фактическое отношение средней прибыли к средним потерям. Коэффициент 0,75 означает, что мы нацелены на три четверти того, чем мы рискуем.
Theoretical Risk Reward = 2.00 # Simulated Ratio
Realized Risk Reward    = 0.75 # Simulated Ratio

Коэффициент прибыли - это относительно быстрый и простой метод расчета прибыльности стратегии. Он рассчитывается как общая валовая прибыль по сравнению с общим валовым убытком в абсолютных значениях, следовательно, интерпретация коэффициента прибыли (также называемого на жаргоне индексом рентабельности корпоративных финансов) - это размер прибыли на 1 доллар убытков. Формула коэффициента прибыли:

Profit factor   =  1.34 # Simulated Profit Factor

Ожидание - это гибкий показатель, представленный известным Лораном Бернатом, который складывается из среднего выигрыша / проигрыша и отношения попаданий. Он обеспечивает ожидаемую прибыль или убыток по фигуре в долларах, взвешенной по коэффициенту попадания. Процент выигрыша - это то, что мы называем коэффициентом попадания в приведенной ниже формуле, и, следовательно, коэффициент проигрыша равен 1 - коэффициенту совпадения.

Expectancy      =  $ 1.33 per trade # Simulated Expectancy

Еще один интересный показатель - количество сделок. Это просто для того, чтобы понять частоту наших сделок.

Trades          = 3697 # Simulated Number

Теперь мы готовы отображать все вышеперечисленные показатели одновременно. После вычисления функции индексатора мы можем использовать приведенную ниже функцию производительности, чтобы получить нужные нам показатели:

def performance(indexer, Data, name):
    
    # Profitability index
    indexer = np.delete(indexer, 0, axis = 1)
    indexer = np.delete(indexer, 0, axis = 1)
    
    profits = []
    losses  = []
    np.count_nonzero(Data[:, 7])
    np.count_nonzero(Data[:, 8])
    
    for i in range(len(indexer)):
        
        if indexer[i, 0] > 0:
            value    = indexer[i, 0]
            profits  = np.append(profits, value)
            
        if indexer[i, 0] < 0:
            value    = indexer[i, 0]
            losses   = np.append(losses, value)
    
    # Hit ratio calculation
    hit_ratio = round((len(profits) / (len(profits) + len(losses))) * 100, 2)
    
    realized_risk_reward = round(abs(profits.mean() / losses.mean()), 2)
    
    # Expected and total profits / losses
    expected_profits = np.mean(profits)
    expected_losses  = np.abs(np.mean(losses))
    total_profits    = round(np.sum(profits), 3)
    total_losses     = round(np.abs(np.sum(losses)), 3)
    
    # Expectancy
    expectancy    = round((expected_profits * (hit_ratio / 100)) \
                   - (expected_losses * (1 - (hit_ratio / 100))), 2)
        
    # Largest Win and Largest Loss
    largest_win = round(max(profits), 2)
    largest_loss = round(min(losses), 2)        
 
    # Total Return
    indexer = Data[:, 10:12]    
    
    # Creating a combined array for long and short returns
    z = np.zeros((len(Data), 1), dtype = float)
    indexer = np.append(indexer, z, axis = 1)
    
    # Combining Returns
    for i in range(len(indexer)):
        try:    
          if indexer[i, 0] != 0:
             indexer[i, 2] = indexer[i, 0] - (expected_cost / lot)
                
          if indexer[i, 1] != 0:
             indexer[i, 2] = indexer[i, 1] - (expected_cost / lot)
        except IndexError:
            pass
        
    # Switching to monetary values
    indexer[:, 2] = indexer[:, 2] * lot
    
    # Creating a portfolio balance array
    indexer = np.append(indexer, z, axis = 1)
    indexer[:, 3] = investment 
    
    # Adding returns to the balance    
    for i in range(len(indexer)):
    
        indexer[i, 3] = indexer[i - 1, 3] + (indexer[i, 2])
    
    indexer = np.array(indexer)
    
    total_return = (indexer[-1, 3] / indexer[0, 3]) - 1
    total_return = total_return * 100
    
    
    print('-----------Performance-----------', name)
    print('Hit ratio       = ', hit_ratio, '%')
    print('Net profit      = ', '$', round(indexer[-1, 3] - indexer[0, 3], 2))
    print('Expectancy      = ', '$', expectancy, 'per trade')
    print('Profit factor   = ' , round(total_profits / total_losses, 2)) 
    print('Total Return    = ', round(total_return, 2), '%')
    print('')    
    print('Average Gain    = ', '$', round((expected_profits), 2), 'per trade')
    print('Average Loss    = ', '$', round((expected_losses * -1), 2), 'per trade')
    print('Largest Gain    = ', '$', largest_win)
    print('Largest Loss    = ', '$', largest_loss)    
    print('')
    print('Realized RR     = ', realized_risk_reward)
    print('Minimum         =', '$', round(min(indexer[:, 3]), 2))
    print('Maximum         =', '$', round(max(indexer[:, 3]), 2))
    print('Trades          =', len(profits) + len(losses))
# Using the function
performance(equity_curve, my_data, 'EURUSD)

Это должно дать нам что-то вроде следующего:

-----------Performance----------- EURUSD
Hit ratio       =  42.28 %
Net profit      =  $ 1209.4
Expectancy      =  $ 0.33 per trade
Profit factor   =  1.01
Total Return    =  120.94 %
Average Gain    =  $ 56.95 per trade
Average Loss    =  $ -41.14 per trade
Largest Gain    =  $ 347.5
Largest Loss    =  $ -311.6Realized RR     =  1.38
Minimum         = $ -1957.6
Maximum         = $ 4004.2
Trades          = 3697
# All of the above are simulated results and do not reflect the presented strategy or indicator

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



Заключение и важный отказ от ответственности

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

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

Подводя итог, можно ли сказать, что стратегии, которые я предлагаю, реалистичны? Да, но только путем оптимизации среды (надежный алгоритм, низкие затраты, честный брокер, надлежащее управление рисками и управление заказами). Предусмотрены ли стратегии исключительно для торговли? Нет, это нужно для стимулирования мозгового штурма и получения новых торговых идей, поскольку мы все устали слышать о перепроданности RSI как о причине для открытия короткой позиции или о преодолении сопротивления как о причине идти долго. Я пытаюсь представить новую область под названием «Объективный технический анализ», в которой мы используем достоверные данные для оценки наших методов, а не полагаемся на устаревшие классические методы.

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