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