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

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

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

Я только что опубликовал новую книгу после успеха Новые технические индикаторы в 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

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

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)

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



Скользящая средняя Фибоначчи

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

Числа находятся путем сложения двух предыдущих чисел после них. В случае 13 оно рассчитывается как 8 + 5, следовательно, формула:

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

def fib(n):
   if n == 1:
      return 1
  
   elif n == 0:   
      return 0 
           
   else:                      
      return fib(n - 1) + fib(n - 2)

Вышеупомянутая функция дает нам число Фибоначчи в соответствии с его индексом. Индекс - это просто порядок чисел, указанных в таблице ниже.

Теперь, если мы воспользуемся функцией и посмотрим на ее результаты, мы поймем лучше.

fib(14)
# Output: 377
fib(5)
# Output: 5

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

  • Мы вычисляем экспоненциальные скользящие средние, используя следующие периоды ретроспективного анализа {2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597}.
  • Делим сумму экспоненциальных скользящих средних на их количество. В нашем случае мы разделим на 15. Мы можем выбрать столько периодов ретроспективного анализа, сколько захотим, и разделить на их количество.
  • Постройте скользящую среднюю Фибоначчи рядом с рыночной ценой.

Но что такое экспоненциальная скользящая средняя? И если на то пошло, что такое скользящая средняя?

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

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

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

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 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 enhanced_fibonnaci_moving_average(Data, where):
    
    # Adding Columns
    Data = adder(Data, 40)
    
    # Calculating Different Moving Averages
    Data = ema(Data, 2, 3,    1, where)
    Data = ema(Data, 2, 5,    1, where + 1)    
    Data = ema(Data, 2, 8,    1, where + 2)    
    Data = ema(Data, 2, 13,   1, where + 3)    
    Data = ema(Data, 2, 21,   1, where + 4)    
    Data = ema(Data, 2, 34,   1, where + 5)    
    Data = ema(Data, 2, 55,   1, where + 6)    
    Data = ema(Data, 2, 89,   1, where + 7)    
    Data = ema(Data, 2, 144,  1, where + 8)    
    Data = ema(Data, 2, 233,  1, where + 9)    
    Data = ema(Data, 2, 377,  1, where + 10)    
    Data = ema(Data, 2, 610,  1, where + 11)    
    Data = ema(Data, 2, 987,  1, where + 12)    
    Data = ema(Data, 2, 1597, 1, where + 13) 
    Data = ema(Data, 2, 2584, 1, where + 14) 
    Data = ema(Data, 2, 4181, 1, where + 15) 
    Data = ema(Data, 2, 6765, 1, where + 16)
    Data[:, where + 17] = Data[:, where] +  Data[:, where + 1] + Data[:, where + 2] + Data[:, where + 3] + Data[:, where + 4] + Data[:, where + 5] + Data[:, where + 6] + Data[:, where + 7] + Data[:, where + 8] + Data[:, where + 9] + Data[:, where + 10] + Data[:, where + 11] + Data[:, where + 12] + Data[:, where + 13] + Data[:, where + 14] + Data[:, where + 15] + Data[:, where + 16]
Data[:, where + 17] = Data[:, where + 17] / 17
Data = deleter(Data, 4, 17)
 
    # Calculating Different Moving Averages
    Data = ema(Data, 2, 3,    2, where + 1)
    Data = ema(Data, 2, 5,    2, where + 2)    
    Data = ema(Data, 2, 8,    2, where + 3)    
    Data = ema(Data, 2, 13,   2, where + 4)    
    Data = ema(Data, 2, 21,   2, where + 5)    
    Data = ema(Data, 2, 34,   2, where + 6)    
    Data = ema(Data, 2, 55,   2, where + 7)    
    Data = ema(Data, 2, 89,   2, where + 8)    
    Data = ema(Data, 2, 144,  2, where + 9)    
    Data = ema(Data, 2, 233,  2, where + 10)    
    Data = ema(Data, 2, 377,  2, where + 11)    
    Data = ema(Data, 2, 610,  2, where + 12)    
    Data = ema(Data, 2, 987,  2, where + 13)    
    Data = ema(Data, 2, 1597, 2, where + 14) 
    Data = ema(Data, 2, 2584, 2, where + 15) 
    Data = ema(Data, 2, 4181, 2, where + 16) 
    Data = ema(Data, 2, 6765, 2, where + 17)  
    
    Data[:, where + 18] = Data[:, where + 1] + Data[:, where + 2] +  Data[:, where + 3] + Data[:, where + 4] + Data[:, where + 5] + Data[:, where + 6] + Data[:, where + 7] + Data[:, where + 8] + Data[:, where + 9] + Data[:, where + 10] + Data[:, where + 11] + Data[:, where + 12] + Data[:, where + 13] + Data[:, where + 14] + Data[:, where + 15] + Data[:, where + 16] + Data[:, where + 17]
Data[:, where + 18] = Data[:, where + 18] / 17
Data = deleter(Data, 5, 17)
    
    return Data

Создание сигналов

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

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

На приведенном ниже графике показаны почасовые значения EURUSD с его 14-периодным нормализованным индексом.

Мы можем выбрать следующие торговые условия:

  • Открывайте длинную позицию (покупайте), когда Нормализованный индекс равен нулю, в то время как рынок одновременно находится выше зоны минимума скользящей средней Фибоначчи, но ниже зоны максимума скользящей средней Фибоначчи. Это приравнивается к тому, что текущий ценовой бар находится между двумя линиями (то есть на уровне поддержки или ниже сопротивления в зависимости от сигнала нормализованного индекса).
  • Открывайте короткую позицию (продавайте), когда Нормализованный индекс равен 100, в то время как рынок одновременно находится выше своей нижней зоны скользящей средней Фибоначчи, но ниже ее верхней зоны. Это равносильно тому, что текущий ценовой бар находится между двумя линиями (то есть на уровне поддержки или ниже сопротивления в зависимости от сигнала нормализованного индекса).

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

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

def signal(Data, close, efma_high, efma_low, normalized_col, buy, sell):
    
    for i in range(len(Data)):
        if Data[i, close] < Data[i, efma_high] and Data[i, close] > Data[i, efma_low] and Data[i, normalized_col] == 0:
                Data[i, buy] = 1
         
        elif Data[i, close] < Data[i, efma_high] and Data[i, close] > Data[i, efma_low] and Data[i, normalized_col] == 100:
                Data[i, sell] = -1
                
    return Data

Выше показан тот же метод, примененный к почасовым значениям USDCHF.

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

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



Рамки оценки стратегии

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

В приведенной выше таблице говорится, что нам нужен индикатор или генератор сигналов в столбце 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 Profit

Быстрый взгляд на среднюю прибыль по сделкам и средний убыток может помочь нам лучше управлять нашими рисками. Например, если наша средняя прибыль составляет 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.6
Realized 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 как о причине для открытия короткой позиции или о преодолении сопротивления как о причине идти долго. Я пытаюсь представить новую область под названием «Объективный технический анализ», в которой мы используем достоверные данные для оценки наших методов, а не полагаемся на устаревшие классические методы.