Создание и кодирование совокупного индекса свечного паттерна в Python.

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

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

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



Введение в свечные графики

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

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

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

Обратите внимание, что вы можете загрузить данные вручную или с помощью Python. Если у вас есть файл Excel, который содержит данные только OHLC, начиная с первой строки и столбца, вы можете импортировать его, используя приведенный ниже фрагмент кода:

import numpy as np
import pandas as pd
# Importing the Data
my_ohlc_data = pd.read_excel('my_ohlc_data.xlsx')
# Converting to Array
my_ohlc_data = np.array(my_ohlc_data)

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

# Importing the necessary charting library
import matplotlib.pyplot as plt
# The syntax to plot a line chart
plt.plot(my_ohlc_data, color = 'black', label = 'EURUSD')
# The syntax to add the label created above
plt.legend()
# The syntax to add a grid
plt.grid()

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

  • Выберите период ретроспективного анализа. Это количество значений, которые вы хотите отобразить на диаграмме.
  • Постройте вертикальные линии для каждой строки, представляющей максимумы и минимумы. Например, для данных OHLC мы будем использовать функцию matplotlib, называемую vlines, которая строит вертикальную линию на диаграмме, используя минимальное (низкое) значение и максимальное (высокое значение).
  • Создайте цветовое условие, которое гласит, что если цена закрытия больше, чем цена открытия, выполнить выбранный блок кода (который, естественно, содержит зеленый цвет). Сделайте это с красным цветом (медвежья свеча) и черным цветом (свеча доджи).
  • Постройте вертикальные линии, используя условия с минимальным и максимальным значениями, представляющими цены закрытия и цены открытия. Убедитесь, что ширина линии слишком велика, чтобы тело свечи выглядело достаточно, чтобы график считался свечным.

def ohlc_plot(Data, window, name):
    
    Chosen = Data[-window:, ]
    
    for i in range(len(Chosen)):
 
      plt.vlines(x = i, ymin = Chosen[i, 2], ymax = Chosen[i, 1], color = 'black', linewidth = 1)
        
      if Chosen[i, 3] > Chosen[i, 0]:
            color_chosen = 'green'
            plt.vlines(x = i, ymin = Chosen[i, 0], ymax = Chosen[i, 3], color = color_chosen, linewidth = 4)              
      if Chosen[i, 3] < Chosen[i, 0]:
            color_chosen = 'red'
            plt.vlines(x = i, ymin = Chosen[i, 3], ymax = Chosen[i, 0], color = color_chosen, linewidth = 4)  
            
      if Chosen[i, 3] == Chosen[i, 0]:
            color_chosen = 'black'
            plt.vlines(x = i, ymin = Chosen[i, 3], ymax = Chosen[i, 0], color = color_chosen, linewidth = 4)  
          
    plt.grid()
    plt.title(name)
# Using the function
ohlc_plot(my_ohlc_data, 50, '')

# 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

Введение в свечные модели

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

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

Паттерн «Бычий доджи» состоит из свечи, цена закрытия которой равна цене открытия. Обычно это происходит после нисходящего движения цены и считается бычьим разворотом или паттерном коррекции.

Паттерн «Бычий доджи» основан на психологии, согласно которой баланс сил уравнялся после изменения тренда в одном направлении. Теоретически мы должны покупать на закрытии второй и последней свечи, чтобы подтвердить паттерн. Чтобы бычий паттерн Доджи был действителен, нам нужна бычья свеча после него.

Паттерн «Медвежий доджи» состоит из свечи, цена закрытия которой равна цене открытия. Обычно это происходит после восходящего движения цены и считается медвежьим разворотом или паттерном коррекции.

Паттерн «Медвежий доджи» основан на психологии, согласно которой баланс сил выровнялся после движения в одном направлении. Теоретически мы должны продавать на закрытии второй и последней свечи, чтобы подтвердить паттерн. Чтобы медвежий паттерн Доджи был действителен, нам нужна медвежья свеча после него.

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



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

Создание индикатора свечи

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

  • Шаблон доджи.
  • Выкройка "Молоток".
  • Звездный узор.
  • Узор "Бутылка".
  • Рисунок "Пирсинг".
  • Образец Харами.
  • Узор Марубозу.
  • Шаблон "Три солдата / вороны".
  • Модель поглощения.
  • Шаблон "Три метода".
  • Шаблон Strike.

Код индикатора будет предоставлен в конце этого раздела, так как он немного длинный. Стоит отметить, что индикатор as обнаруживает каждый раз, когда паттерн подтверждается, и вводит 1, если он бычий, и -1, если он медвежий. Это означает, что значение +2 означает, что две бычьи модели были подтверждены на одних и тех же гистограммах. В приведенных ниже примерах показаны сигналы, основанные как минимум на показаниях +2 или -2, что обеспечивает наличие как минимум двух паттернов на одном столбчатом графике.

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

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

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

Медвежий сигнал возник выше и привел к некоторой слабости. Обратите внимание, что сразу после него был слабый бычий сигнал только от одного паттерна (значение 1), поэтому алгоритм его пропустил.

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

# Defining the minimum width of the candle
body_hammer = 0.0004
wick = body_hammer * 2
def signal_hammer(Data):
    
    for i in range(len(Data)):        
       
       # Hammer
       if abs(Data[i, 3] - Data[i, 0]) < body_hammer and abs(Data[i, 2] - Data[i, 0]) > wick and Data[i, 1] == Data[i, 0]:
            
                Data[i, 6] = 1 
           
       # Hammer
       if abs(Data[i, 3] - Data[i, 0]) < body_hammer and abs(Data[i, 2] - Data[i, 0]) > wick and Data[i, 1] == Data[i, 3]:
            
                Data[i, 6] = 1 
                
       # Shooting Star
       if abs(Data[i, 3] - Data[i, 0]) < body_hammer and abs(Data[i, 1] - Data[i, 0]) > wick and Data[i, 2] == Data[i, 0]:
   
               Data[i, 7] = -1  
    
       # Shooting Star
       if abs(Data[i, 3] - Data[i, 0]) < body_hammer and abs(Data[i, 1] - Data[i, 0]) > wick and Data[i, 2] == Data[i, 3]:
   
               Data[i, 7] = -1
# Defining the minimum width of the first and third candles
side_body = 0.0010
# Defining the maximum width of the second candle
middle_body = 0.0003
# Signal function
def signal_star(Data):
    
    for i in range(len(Data)):        
       
       # Morning Star
       if Data[i - 2, 3] < Data[i - 2, 0] and (Data[i - 2, 0] - Data[i - 2, 3]) > side_body and (abs(Data[i - 1, 3] - Data[i - 1, 0])) <= middle_body and Data[i, 3] > Data[i, 0] and (Data[i, 3] - Data[i, 0]) > side_body:
            
                Data[i, 8] = 1 
                  
       # Evening Star
       if Data[i - 2, 3] > Data[i - 2, 0] and (Data[i - 2, 3] - Data[i - 2, 0]) > side_body and (abs(Data[i - 1, 3] - Data[i - 1, 0])) <= middle_body and Data[i, 3] < Data[i, 0] and (Data[i, 3] - Data[i, 0]) > side_body:
    
               Data[i, 9] = -1
def signal_bottle(Data):
    
    for i in range(len(Data)):        
       
       # Bullish Bottle
       if Data[i, 3] > Data[i, 0] and Data[i, 0] == Data[i, 2]: 
                Data[i, 10] = 1 
           
       # Bearish Bottle
       if Data[i, 3] < Data[i, 0] and Data[i, 0] == Data[i, 1]: 
                Data[i, 11] = -1
body_piercing = 0.0005
def signal_piercing(Data):
    
    for i in range(len(Data)):        
       
       # Bullish Piercing
       if Data[i - 1, 3] > Data[i, 0] and \
          Data[i - 1, 0] > Data[i, 3] and \
          Data[i - 1, 3] < Data[i, 3] and \
          Data[i - 1, 1] > Data[i, 1] and \
          Data[i - 1, 2] > Data[i, 2] and \
          Data[i - 1, 3] < Data[i - 1, 0] and \
          Data[i, 3] > Data[i, 0] and \
          Data[i, 3] - Data[i, 0] > body_piercing: 
              
                Data[i, 12] = 1 
           
       # Bearish Piercing
       if Data[i - 1, 3] < Data[i, 0] and \
          Data[i - 1, 0] < Data[i, 3] and \
          Data[i - 1, 3] > Data[i, 3] and \
          Data[i - 1, 1] < Data[i, 1] and \
          Data[i - 1, 2] < Data[i, 2] and \
          Data[i - 1, 3] > Data[i - 1, 0] and \
          Data[i, 3] < Data[i, 0] and \
          Data[i, 0] - Data[i, 3] > body_piercing:           
            
                Data[i, 13] = -1
def signal_harami(Data):
    
    for i in range(len(Data)):        
       
       # Bullish Harami
       if Data[i, 1] < Data[i - 1, 1] and Data[i, 2] > Data[i - 1, 2] and Data[i, 3] < Data[i - 1, 0] and Data[i, 0] > Data[i - 1, 3] and Data[i, 3] > Data[i, 0] and Data[i - 1, 3] < Data[i - 1, 0]:
            
                Data[i, 14] = 1 
           
       
       # Bearish Harami
       if Data[i, 1] < Data[i - 1, 1] and Data[i, 2] > Data[i - 1, 2] and Data[i, 3] > Data[i - 1, 0] and Data[i, 0] < Data[i - 1, 3] and Data[i, 3] < Data[i, 0] and Data[i - 1, 3] > Data[i - 1, 0]:
    
               Data[i, 15] = -1
def signal_marubozu(Data):
    
    for i in range(len(Data)):        
       
       # Bullish Marubozu
       if Data[i, 3] > Data[i, 0] and Data[i, 1] == Data[i, 3] and Data[i, 2] == Data[i, 0]:
            
                Data[i, 16] = 1 
              
       # Bearish Marubozu
       if Data[i, 3] < Data[i, 0] and Data[i, 1] == Data[i, 0] and Data[i, 2] == Data[i, 3]:
    
               Data[i, 17] = -1
# Defining the minimum width of the candle
body_three = 0.0005
def signal_three(Data, body_three):
    
    for i in range(len(Data)):        
       
       # Three White Soldiers
       if Data[i, 3] > Data[i, 0] and (Data[i, 3] - Data[i, 0]) >= body_three and Data[i, 3] > Data[i - 1, 3] and Data[i - 1, 3] > Data[i - 1, 0] and (Data[i - 1, 3] - Data[i - 1, 0]) >= body_three and Data[i - 1, 3] > Data[i - 2, 3] and Data[i - 2, 3] > Data[i - 2, 0] and (Data[i - 2, 3] - Data[i - 2, 0]) >= body_three and Data[i - 2, 3] > Data[i - 3, 3]:
            
          Data[i, 18] = 1 
           
       
       # Three Black Crows
       if Data[i, 3] < Data[i, 0] and (Data[i, 0] - Data[i, 3]) >= body_three and Data[i, 3] < Data[i - 1, 3] and Data[i - 1, 3] < Data[i - 1, 0] and (Data[i - 1, 0] - Data[i - 1, 3]) >= body_three and Data[i - 1, 3] < Data[i - 2, 3] and Data[i - 2, 3] < Data[i - 2, 0] and (Data[i - 2, 0] - Data[i - 2, 3]) >= body_three and Data[i - 2, 3] < Data[i - 3, 3]:
    
         Data[i, 19] = -1
# Defining the minimum width of the candle
body_engulfing = 0.0005
def signal_engulfing(Data, body_engulfing):
    
    for i in range(len(Data)):        
       
       # Bullish Engulfing
       if Data[i, 3] > Data[i, 0] and Data[i - 1, 3] < Data[i - 1, 0] and (Data[i, 3] - Data[i, 0]) >= body_engulfing and Data[i, 1] > Data[i - 1, 1] and Data[i, 2] < Data[i - 1, 2] and Data[i, 3] > Data[i - 1, 0] and Data[i, 0] < Data[i - 1, 3]:
            
                Data[i, 20] = 1 
           
       # Bearish Engulfing
       if Data[i, 3] < Data[i, 0] and Data[i - 1, 3] > Data[i - 1, 0] and (Data[i, 3] - Data[i, 0]) >= body_engulfing and Data[i, 1] < Data[i - 1, 1] and Data[i, 2] > Data[i - 1, 2] and Data[i, 3] < Data[i - 1, 0] and Data[i, 0] > Data[i - 1, 3] :
    
               Data[i, 21] = -1
               
# Defining the minimum width of the candle
body_method = 0.0005
# Defining the window of trend
window = 5               
               
def signal_methods(Data):
    
    for i in range(len(Data)):        
       
       # Falling Three Methods
       if Data[i, 3] < Data[i, 0] and Data[i, 3] < Data[i - 3, 2] and (Data[i, 0] - Data[i, 3]) > body_method and \
          Data[i - 1, 3] > Data[i - 1, 0] and Data[i - 1, 3] > Data[i - 2, 3] and \
          Data[i - 2, 3] > Data[i - 2, 0] and Data[i - 2, 3] > Data[i - 3, 3] and \
          Data[i - 1, 3] > Data[i - 3, 0] and Data[i - 3, 3] > Data[i - 4, 3] and \
          Data[i - 3, 3] < Data[i - window, 3]: 
              
                Data[i, 23] = -1 
           
       # Rising Three Methods
       if Data[i, 3] > Data[i, 0] and Data[i, 3] > Data[i - 3, 2] and (Data[i, 0] - Data[i, 3]) > body_method and \
          Data[i - 1, 3] < Data[i - 1, 0] and Data[i - 1, 3] < Data[i - 2, 3] and \
          Data[i - 2, 3] < Data[i - 2, 0] and Data[i - 2, 3] < Data[i - 3, 3] and \
          Data[i - 1, 3] < Data[i - 3, 0] and Data[i - 3, 3] < Data[i - 4, 3] and \
          Data[i - 3, 3] > Data[i - window, 3]:            
            
                Data[i, 22] = 1               
               
def signal_strike(Data):
    for i in range(len(Data)):
            
        if Data[i - 3, 3] > Data[i - 3, 0] and Data[i - 2, 3] > Data[i - 3, 3]  and Data[i - 2, 3] > Data[i - 3, 3] and Data[i - 1, 3] > Data[i - 2, 3] and Data[i, 3] < Data[i - 3, 2] and Data[i, 1] > Data[i - 1, 3]:
            Data[i, 24] = 1
            
        if Data[i - 3, 3] < Data[i - 3, 0] and Data[i - 2, 3] < Data[i - 3, 3]  and Data[i - 2, 3] < Data[i - 3, 3] and Data[i - 1, 3] < Data[i - 2, 3] and Data[i, 3] > Data[i - 3, 1] and Data[i, 2] < Data[i - 1, 3]:
            Data[i, 25] = -1
my_data = adder(my_data, 30)
signal_hammer(my_data)
signal_star(my_data)
signal_bottle(my_data)
signal_piercing(my_data)
signal_harami(my_data)
signal_marubozu(my_data)
signal_three(my_data, body_three)
signal_engulfing(my_data, body_engulfing)
signal_methods(my_data)
signal_strike(my_data)
my_data[:, 26] = my_data[:, 6] + my_data[:, 8] + my_data[:, 10] + my_data[:, 12] + my_data[:, 14] + my_data[:, 16] + my_data[:, 18] + my_data[:, 20] + my_data[:, 22] + my_data[:, 24]
 
my_data[:, 27] = my_data[:, 7] + my_data[:, 9] + my_data[:, 11] + my_data[:, 13] + my_data[:, 15] + my_data[:, 17] + my_data[:, 19] + my_data[:, 21] + my_data[:, 23] + my_data[:, 25] 
my_data = deleter(my_data, 5, 21)
my_data[:, 7] = my_data[:, 5] + my_data[:, 6]
 
my_data = deleter(my_data, 5, 2)
for i in range(len(my_data)):
    
    if my_data[i, 5] > 1:
        my_data[i, 6] = 1
elif my_data[i, 5] < -1:
        my_data[i, 7] = -1
for i in range(len(Asset1)):
    
    if Asset1[i, 5] > 1:
        Asset1[i, 6] = 1
elif Asset1[i, 5] < -1:
        Asset1[i, 7] = -1

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



Заключение

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

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

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