Кодирование индекса истинной силы и тестирование торговой стратегии на Python

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

В этой статье мы сначала построим некоторые базовые интуитивные представления об индикаторе и о том, как он рассчитывается, или о математике, лежащей в его основе. Затем мы перейдем к части программирования, где мы будем использовать Python для создания индикатора с нуля, построения торговой стратегии, тестирования стратегии и сравнения результатов с результатами SPY ETF (ETF, специально разработанный для отслеживания движения рыночного индекса S & P 500). Без дальнейших церемоний давайте перейдем к статье!

Прежде чем двигаться дальше, если вы хотите протестировать свои торговые стратегии без какого-либо кодирования, для этого есть решение. Это зона тестирования. Это платформа для тестирования любого количества торговых стратегий на различных типах торгуемых активов бесплатно без кодирования. Вы можете сразу же использовать инструмент, перейдя по ссылке здесь: https://www.backtestzone.com /

Индекс истинной силы (TSI)

Индекс истинной силы (TSI) — это осциллятор импульса, который в основном используется трейдерами для определения того, является ли рынок восходящим или нисходящим импульсом, и торговли вместе с ним. Он также используется для определения текущего состояния рынка, перекупленности или перепроданности, но это не является основной сильной стороной индикатора. Индекс истинной силы состоит из двух компонентов:

  • Линия TSI: первым компонентом является сама линия TSI, которая рассчитывается путем первого определения фактического изменения цены (текущая цена закрытия минус предыдущая цена закрытия) и абсолютного изменения цены (абсолютные значения фактического изменения цены). Затем для фактического изменения цены и абсолютного изменения цены берется EMA с 25 в качестве количества периодов (длинных). Затем эти два EMA снова сглаживаются с помощью экспоненциальной скользящей средней за 13-дневный период (короткой). Этот процесс сглаживания ряда данных с помощью двух EMA известен как двойное сглаживание, и целью этого является устранение шума в данных. Теперь дважды сглаженное фактическое изменение цены делится на дважды сглаженное абсолютное изменение цены, а затем умножается на 100, чтобы получить показания линии TSI. Обратите внимание, что параметры (25, 13), которые мы приняли во внимание, являются типичными настройками, но могут быть настроены соответствующим образом. Расчет может быть нечетким, но его можно легко понять, если мы интерпретируем его в виде формулы или представления:
СТРОКА TSI = [ DS. ФАКТИЧЕСКИЙ ПК / DS. АБСОЛЮТНЫЙ ПК ] * 100 где, DS. ФАКТИЧЕСКИЙ ПК = двойное сглаженное фактическое изменение цены с длиной 25 и 13 DS. АБСОЛЮТНЫЙ ПК = двойное сглаженное абсолютное изменение цены длиной 25 и 13
  • Сигнальная линия: следующий компонент — это компонент сигнальной линии, который представляет собой не что иное, как экспоненциальную скользящую среднюю TSI за указанное количество периодов (от 7 до 12 периодов). Большинство трейдеров предпочитают периоды, близкие к 7, для целей дневной торговли и близкие к 12 для долгосрочного инвестирования. В этой статье мы будем использовать 12 в качестве количества периодов, поскольку мы будем иметь дело с данными о запасах на дневном таймфрейме, а не с минутным таймфреймом. Расчет может быть представлен следующим образом:
СИГНАЛЬНАЯ ЛИНИЯ = EXP.MA 13 [ ЛИНИЯ TSI ]

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

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

Теперь давайте посмотрим, как можно использовать TSI для определения того, находится ли рынок в состоянии перекупленности или перепроданности. Обычно такие индикаторы, как RSI, имеют стандартный порог уровней перекупленности и перепроданности, который составляет 70 и 30 соответственно, и эти пороговые значения применимы к любому торгуемому активу. Принимая во внимание, что уровни перекупленности и перепроданности варьируются от одного актива к другому при использовании индекса истинной силы, и в нашем случае мы могли бы рассматривать -10 как уровень перепроданности, а 10 — как уровень перекупленности. Но все же он не будет таким эффективным, как другие популярные импульсные осцилляторы.

Говоря о торговых стратегиях, насколько мне известно, мы могли бы применять три типа стратегий, основанных на индексе истинной силы. Первый — это уровни перекупленности и перепроданности. Это наиболее распространенная стратегия среди осцилляторов импульса, которая показывает сигнал на покупку всякий раз, когда компоненты TSI опускаются ниже уровня перепроданности, а сигнал на продажу генерируется всякий раз, когда показания обоих компонентов поднимаются выше уровня перекупленности. Я лично не использую эту стратегию, поскольку считаю, что индекс истинной силы не имеет хорошей истории с концепцией уровней перекупленности и перепроданности.

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

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

ЕСЛИ ПРЕДЫДУЩЕЕ.TLINE < ПРЕДЫДУЩАЯ СТРОКА И ТЕКУЩАЯ СТРОКА.TLINE > ТЕКУЩАЯ СТРОКА ==> СИГНАЛ НА ПОКУПКУ
ЕСЛИ ПРЕДЫДУЩЕЕ.TLINE > ПРЕДЫДУЩАЯ СТРОКА И ТЕКУЩАЯ.TLINE < ТЕКУЩАЯ СТРОКА ==> СИГНАЛ НА ПРОДАЖУ

Вот и все! На этом наша теоретическая часть об индексе истинной силы заканчивается. Теперь давайте перейдем к программированию, где мы будем использовать Python для создания индикатора с нуля, построения торговой стратегии пересечения сигнальных линий, тестирования стратегии на данных акций Apple и сравнения результатов с результатами SPY ETF. Давайте немного поработаем с кодом! Прежде чем двигаться дальше, примечание об отказе от ответственности: единственной целью этой статьи является просвещение людей, и ее следует рассматривать как информационный материал, а не как инвестиционный совет или что-то в этом роде.

Реализация на Python

Часть кодирования подразделяется на несколько этапов следующим образом:

1. Импорт пакетов
2. Извлечение биржевых данных из двенадцати данных
3. Расчет индекса истинной силы
4. Создание торговой стратегии пересечения сигнальных линий
5. Построение торговых списков
6. Создаем нашу позицию
7. Тестирование
8. Сравнение SPY ETF

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

Шаг 1: Импорт пакетов

Импорт необходимых пакетов в среду python — это шаг, который нельзя пропустить. Основными пакетами будут Pandas для работы с данными, NumPy для работы с массивами и сложными функциями, Matplotlib для построения графиков и запросов для выполнения вызовов API. Вторичными пакетами будут Math для математических функций и Termcolor для настройки шрифта (необязательно).

Реализация на Python:

# ИМПОРТ ПАКЕТОВ

импортируйте pandas как
запросы
на импорт pd импортируйте matplotlib.pyplot как plt
импортируйте numpy как np
из math импортируйте floor
из termcolor импортируйте colored как cl

plt.style.use('fivethirtyeight')
plt.rcParams['figure.figsize'] = (20,10)

Теперь, когда мы импортировали все необходимые пакеты в наш python. Давайте извлекем исторические данные Apple с помощью конечной точки API Twelve Data.

Шаг 2: извлечение данных из двенадцати данных

На этом этапе мы собираемся извлечь исторические данные о запасах Apple, используя конечную точку API, предоставленную twelvedata.com . Перед этим примечание о twelvedata.com : Twelve Data — один из ведущих поставщиков рыночных данных, обладающий огромным количеством конечных точек API для всех типов рыночных данных. Очень легко взаимодействовать с API, предоставляемыми Twelve Data, и имеет одну из лучших когда-либо документации. Кроме того, убедитесь, что у вас есть учетная запись на twelvedata.com , только тогда вы сможете получить доступ к своему ключу API (жизненно важный элемент для извлечения данных с помощью API).

Реализация на Python:

# ИЗВЛЕЧЕНИЕ БИРЖЕВЫХ ДАННЫХ

определение get_historical_data(symbol, start_date):
api_key = 'ВАШ КЛЮЧ API'
api_url = f'https://api.twelvedata.com/time_series?symbol={symbol}&interval=1day&outputsize=5000&apikey={api_key} '
raw_df = запросы.get(api_url).json()
df = pd.DataFrame(raw_df['значения']).iloc[::-1].set_index('datetime').astype(float)
df = df[df.index >= start_date]
df.index = pd.to_datetime(df.index)
возвращает df

aapl = get_historical_data('AAPL', '2019-01-01')
aapl.tail()

Объяснение кода: Первое, что мы сделали, это определили функцию с именем ‘get_historical_data’, которая принимает символ акции (‘symbol’) и дату начала исторических данных (‘start_date’) в качестве параметров.Внутри функции мы определяем ключ API и URL-адрес и сохраняем их в соответствующей переменной. Затем мы извлекаем исторические данные в формате JSON с помощью функции ‘get’ и сохраняем их в переменной ‘raw_df’. После выполнения некоторых процессов по очистке и форматированию необработанных данных JSON мы возвращаем их в виде чистого фрейма данных Pandas. Наконец, мы вызываем созданную функцию, чтобы извлечь исторические данные Apple с начала 2019 года и сохранить их в переменной ‘aapl’.

Шаг 3: расчет индекса истинной силы

На этом этапе мы собираемся рассчитать компоненты индекса истинной силы, следуя методам и формуле, которые мы обсуждали ранее.

Реализация на Python:

# РАСЧЕТ ИНДЕКСА ИСТИННОЙ СИЛЫ 

def get_tsi(закрытие, длинная, короткая, сигнал):
diff = close - закрыть.сдвиг(1)
abs_diff = abs(diff)

diff_smoothed = diff.ewm(span = long, adjust = False).mean()
diff_double_smoothed = diff_smoothed.ewm(span = short, adjust = False).mean()
abs_diff_smoothed = abs_diff.ewm(span = long, adjust = False).mean()
abs_diff_double_smoothed = abs_diff_smoothed.ewm(span = short, adjust = False).mean()

tsi = (diff_double_smoothed / abs_diff_double_smoothed) * 100
signal = tsi.ewm(span = signal, adjust = False).mean()
tsi = tsi[tsi.index >= '2020-01-01'].dropna()
сигнал = сигнал[signal.index >= '2020-01-01'].dropna() сигнал = сигнал [signal.index >= '2020-01-01'].)

возврат tsi, сигнал

aapl['tsi'], aapl['signal_line'] = get_tsi(aapl['close'], 25, 13, 12)
aapl = aapl[aapl.index >= '2020-01-01']
aapl.tail()

Объяснение кода: Во-первых, мы определяем функцию с именем ‘get_tsi’, которая принимает данные о цене закрытия акции (‘close’), период ожидания для длинной EMA (‘long’), период ожидания для короткой EMA (‘short’) и период ожидания длясигнальная линия (‘signal’) в качестве параметров. Внутри функции мы сначала вычисляем и сохраняем фактическое изменение цены (‘diff’) и абсолютное изменение цены (‘abs_diff’) в их соответствующую переменную.

Затем, используя функцию ‘ewm’, предоставляемую пакетом Pandas для определения экспоненциальной скользящей средней, мы дважды сглаживаем ранее рассчитанные изменения цен, чтобы получить двойное сглаженное фактическое изменение цены (‘diff_double_smoothed’) и двойное сглаженное абсолютное изменение цены (‘abs_diff_double_smoothed’).

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

Шаг 4: Создание торговой стратегии

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

Реализация на Python:

# СТРАТЕГИЯ ИНДЕКСА ИСТИННОЙ СИЛЫ

определение реализации_tsi_strategy(цены, tsi, signal_line):
buy_price = []
sell_price = []
tsi_signal = []
signal = 0

для i в диапазоне (len(цены)):
если tsi[i-1] <signal_line[i-1] и tsi[i] > signal_line[i]:
если сигнал != 1:
buy_price.append(цены [i])
sell_price.append(np.nan)
сигнал= 1
tsi_signal.append(signal)
else:
buy_price.append(np.nan)
sell_price.append(np.nan)
tsi_signal.append(0)
если tsi[i-1] > signal_line[i-1] и tsi[i] < signal_line[i]:
если сигнал!= -1:
buy_price.append(np.nan)
sell_price.добавить (цены [i])
сигнал = -1
tsi_signal.добавить (сигнал)
еще:
buy_price.добавить(np.nan)
sell_price.добавить(np.nan)
tsi_signal.добавить(0)
еще:
buy_price.добавить(np.nan)
sell_price.добавить(np.nan)
tsi_signal.добавить (0)

возврат buy_price, sell_price, tsi_signal

buy_price, sell_price, tsi_signal = implement_tsi_strategy(aapl['close'], aapl['tsi'], aapl['signal_line'])

Объяснение кода: Сначала мы определяем функцию с именем ‘implement_tsi_strategy’, которая принимает цены акций (‘prices’) и компоненты индекса истинной силы (‘tsi’, ‘signal_line’) в качестве параметров.

Внутри функции мы создаем три пустых списка (buy_price, sell_price и tsi_signal), в которые будут добавлены значения при создании торговой стратегии.

После этого мы реализуем торговую стратегию через цикл for. Внутри цикла for мы передаем определенные условия, и если условия выполняются, соответствующие значения будут добавлены к пустым спискам. Если условие покупки акции будет выполнено, цена покупки будет добавлена в список ‘buy_price’, а значение сигнала будет добавлено как 1, представляющее покупку акции. Аналогично, если условие продажи акций будет выполнено, цена продажи будет добавлена к списку ‘sell_price’, а значение сигнала будет добавлено как -1, представляющее продажу акций.

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

Шаг 5: построение торговых сигналов

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

Реализация на Python:

# ГРАФИК ТОРГОВЫХ СИГНАЛОВ ИНДЕКСА ИСТИННОЙ СИЛЫ

ax1 = plt.subplot2grid((11,1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((11,1), (6,0), rowspan = 5, colspan = 1)
ax1.plot(aapl ['close'], linewidth = 2)
ax1.график (aapl.index, buy_price, marker = '^', markersize = 12, color = 'green', linewidth = 0, label = 'СИГНАЛ НА ПОКУПКУ')
ax1.график (aapl.index, sell_price, marker = 'v', markersize = 12, color = 'r', linewidth = 0, label = 'СИГНАЛ НА ПРОДАЖУ')
ax1.legend()
ax1.set_title('ТОРГОВЫЕ СИГНАЛЫ AAPL TSI')
ax2.plot(aapl['tsi'], linewidth = 2, color = 'оранжевый', label = 'ЛИНИЯ TSI')
ax2.plot(aapl['signal_line'], linewidth = 2, color = '#FF006E', label = 'СИГНАЛЬНАЯ ЛИНИЯ')
ax2.set_title('AAPL TSI 25,13,12')
ax2.legend()
plt.show()

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

Шаг 6: Создание нашей позиции

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

Реализация на Python:

# ПОЗИЦИЯ ПО АКЦИЯМ

позиция = []
для i в диапазоне (len(tsi_signal)):
если tsi_signal[i]> 1:
position.append(0)
иначе:
position.append(1)

для i в диапазоне (len(aapl['close'])):
если tsi_signal[i] == 1:
позиция [i] = 1
, если tsi_signal[i] == -1:
позиция [i] = 0
, иначе:
позиция [i] = позиция [i-1]

close_price = aapl['close']
tsi = aapl['tsi']
signal_line = aapl['signal_line']
tsi_signal = pd.DataFrame(tsi_signal).rename(столбцы = {0:'tsi_signal'}).set_index(aapl.index)
position = pd.DataFrame(позиция).переименовать(столбцы = {0:'tsi_position'}).set_index(aapl.index)

фреймы = [close_price, tsi, signal_line, tsi_signal, position]
strategy = pd.concat(фреймы, соединение = 'inner', ось = 1)

СТРАТЕГИИ

Объяснение кода: Сначала мы создаем пустой список с именем ‘позиция’.Мы передаем два цикла for, один из которых заключается в генерации значений для списка «позиция», чтобы они просто соответствовали длине списка «сигнал». Другой цикл for — это тот, который мы используем для генерации фактических значений позиций. Внутри второго цикла for мы перебираем значения списка ‘signal’, а значения списка ‘position’ добавляются относительно того, какое условие выполняется. Стоимость позиции остается равной 1, если мы держим акции, или остается равной 0, если мы продали или не владеем акциями. Наконец, мы выполняем некоторые манипуляции с данными, чтобы объединить все созданные списки в один фрейм данных.

Из показанного вывода мы можем видеть, что в первых двух строках наша позиция по акциям осталась равной 1 (поскольку в сигнале индекса истинной силы нет никаких изменений), но наша позиция внезапно превратилась в -1, поскольку мы продали акции, когда торговый сигнал индекса истинной силы представляет собой сигнал на продажу(-1). Наша позиция останется равной 0, пока не произойдут некоторые изменения в торговом сигнале. Теперь пришло время реализовать некоторый процесс тестирования!

Шаг 7: тестирование

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

Реализация на Python:

# ТЕСТИРОВАНИЕ

aapl_ret = pd.DataFrame(np.diff(aapl['close'])).переименовать(столбцы = {0:'returns'})
tsi_strategy_ret = []

для i в диапазоне (len(aapl_ret)):
возвращает = aapl_ret['возвращает'][i]* стратегия['tsi_position'][i]
tsi_strategy_ret.append(возвращает)

tsi_strategy_ret_df = pd.DataFrame(tsi_strategy_ret).rename(столбцы = {0:'tsi_returns'})
investment_value = 100000
number_of_stocks = floor(investment_value/aapl['close'][0])
tsi_investment_ret = []

для i в диапазоне(len(tsi_strategy_ret_df['tsi_returns'])):
возвращает = число_из_стоков * tsi_strategy_ret_df['tsi_returns'][i]
tsi_investment_ret.append(возвращает)

tsi_investment_ret_df = pd.DataFrame(tsi_investment_ret).rename(столбцы = {0:'investment_returns'})
total_investment_ret = round(сумма (tsi_investment_ret_df['investment_returns']), 2)
profit_percentage = floor((total_investment_ret/ investment_value)*100)
print(cl('Прибыль, полученная от стратегии tsiинвестировав 100 тысяч долларов в AAPL: {}'.format(total_investment_ret), attrs = ['bold']))
print(cl('Процент прибыли от стратегии tsi: {}%'.format(profit_percentage), attrs = ['bold']))




Объяснение кода: Сначала мы вычисляем доходность акций Apple, используя функцию ‘diff’, предоставляемую пакетом NumPy, и мы сохранили ее как фрейм данных в переменной ‘aapl_ret’. Далее мы передаем цикл for для перебора значений переменной ‘aapl_ret’ для вычисления доходности, полученной от нашей торговой стратегии TSI, и эти возвращаемые значения добавляются в список ‘tsi_strategy_ret’. Затем мы преобразуем список ‘tsi_strategy_ret’ в фрейм данных и сохраняем его в переменной ‘tsi_strategy_ret_df’.

Далее следует процесс тестирования. Мы собираемся протестировать нашу стратегию, вложив в нашу торговую стратегию сто тысяч долларов. Итак, сначала мы сохраняем сумму инвестиций в переменной ‘investment_value’. После этого мы рассчитываем количество акций Apple, которые мы можем купить, используя сумму инвестиций. Вы можете заметить, что я использовал функцию «floor», предоставляемую пакетом Math, потому что при делении суммы инвестиций на цену закрытия акций Apple она выдает результат с десятичными числами. Количество акций должно быть целым числом, а не десятичным числом. Используя функцию «floor», мы можем вырезать десятичные дроби. Помните, что функция «floor» намного сложнее, чем функция «round». Затем мы передаем цикл for для определения доходности инвестиций, за которым следуют некоторые задачи по обработке данных.

Наконец, мы печатаем общую прибыль, которую мы получили, вложив сто тысяч долларов в нашу торговую стратегию, и выясняется, что мы получили приблизительную прибыль в размере семидесяти одной тысячи долларов США за один год. Это неплохо! Теперь давайте сравним нашу доходность с доходностью SPY ETF (ETF, предназначенный для отслеживания индекса фондового рынка S & P 500).

Шаг 8: сравнение шпионских ETF

Этот шаг необязателен, но настоятельно рекомендуется, поскольку мы можем получить представление о том, насколько хорошо наша торговая стратегия работает по сравнению с эталонным показателем (SPY ETF). На этом этапе мы извлекем данные SPY ETF с помощью созданной нами функции get_historical_data и сравним доходность, которую мы получаем от SPY ETF, с доходностью нашей торговой стратегии TSI signal line crossover в Apple.

Возможно, вы заметили, что во всех моих статьях об алгоритмической торговле я сравнивал результаты стратегии не с самим рыночным индексом S & P 500, а с SPY ETF, и это потому, что большинство поставщиков биржевых данных (например, Twelve Data) не предоставляют данные индекса S & P 500. Итак, у меня нет другого выбора, кроме как использовать SPY ETF. Если вам повезло получить данные по индексу рынка S & P 500, рекомендуется использовать его для сравнения, а не какой-либо ETF.

Реализация на Python:

# СРАВНЕНИЕ SPY ETF

определение get_benchmark(start_date, investment_value):
spy = get_historical_data('SPY', start_date)['close']
benchmark = pd.DataFrame(np.diff(spy)).rename(столбцы = {0:'benchmark_returns'})

investment_value = investment_value
number_of_stocks = floor(investment_value / spy[-1])
benchmark_investment_ret = []

для i в диапазоне (len(benchmark['benchmark_returns'])):
returns = number_of_stocks*benchmark['benchmark_returns'][i]
benchmark_investment_ret.append(возвращает)

benchmark_investment_ret_df = pd.DataFrame(benchmark_investment_ret).rename(столбцы = {0:'investment_returns'})
возвращает benchmark_investment_ret_df

benchmark = get_benchmark('2020-01-01', 100000)
investment_value = 100000
total_benchmark_investment_ret = round(сумма (benchmark['investment_returns']), 2)
benchmark_profit_percentage = floor((total_benchmark_investment_ret / investment_value)* 100)
print(cl('Benchmark прибыль от инвестирования $100 тыс.: {}'.format(total_benchmark_investment_ret), attrs = ['bold']))
print(cl('Процент прибыли контрольного показателя: {}%'.format(benchmark_profit_percentage), attrs = ['bold']))
print(cl('Прибыль стратегии TSI на {}% выше, чем прибыль контрольного показателя'.format(profit_percentage - benchmark_profit_percentage), attrs = ['bold']))




Объяснение кода: Код, используемый на этом этапе, почти аналогичен коду, используемому на предыдущем этапе тестирования, но вместо того, чтобы инвестировать в Apple, мы инвестируем в SPY ETF, не применяя никаких торговых стратегий. Из выходных данных мы видим, что наша торговая стратегия пересечения сигнальных линий индекса истинной силы превзошла SPY ETF на 48%. Это здорово!

Заключение

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

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

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

Полный код:

# ИМПОРТ ПАКЕТОВ

импортируйте pandas как
запросы
на импорт pd импортируйте matplotlib.pyplot как plt
импортируйте numpy как np
из math импортируйте floor
из termcolor импортируйте colored как cl

plt.style.use('fivethirtyeight')
plt.rcParams['figure.figsize'] = (20,10)

# ИЗВЛЕЧЕНИЕ БИРЖЕВЫХ ДАННЫХ

определение get_historical_data(symbol, start_date):
api_key = 'ВАШ КЛЮЧ API'
api_url = f'https://api.twelvedata.com/time_series?symbol={symbol}&interval=1day&outputsize=5000&apikey={api_key} '
raw_df = запросы.get(api_url).json()
df = pd.DataFrame(raw_df['значения']).iloc[::-1].set_index('datetime').astype(float)
df = df[df.index >= start_date]
df.index = pd.to_datetime(df.index)
возвращает df

aapl = get_historical_data('AAPL', '2019-01-01')
aapl.tail()

# РАСЧЕТ ИНДЕКСА ИСТИННОЙ СИЛЫ

def get_tsi(закрытие, длинная, короткая, сигнал):
diff = close - закрыть.сдвиг(1)
abs_diff = abs(diff)

diff_smoothed = diff.ewm(span = long, adjust = False).mean()
diff_double_smoothed = diff_smoothed.ewm(span = short, adjust = False).mean()
abs_diff_smoothed = abs_diff.ewm(span = long, adjust = False).mean()
abs_diff_double_smoothed = abs_diff_smoothed.ewm(span = short, adjust = False).mean()

tsi = (diff_double_smoothed / abs_diff_double_smoothed) * 100
signal = tsi.ewm(span = signal, adjust = False).mean()
tsi = tsi[tsi.index >= '2020-01-01'].dropna()
сигнал = сигнал[signal.index >= '2020-01-01'].dropna() сигнал = сигнал [signal.index >= '2020-01-01'].)

возврат tsi, сигнал

aapl['tsi'], aapl['signal_line'] = get_tsi(aapl['close'], 25, 13, 12)
aapl = aapl[aapl.index >= '2020-01-01']
aapl.tail()

# ГРАФИК ИНДЕКСА ИСТИННОЙ СИЛЫ

ax1 = plt.subplot2grid((11,1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((11,1), (6,0), rowspan = 5, colspan = 1)
ax1.plot(aapl ['close'], ширина линии = 2,5)
ax1.set_title('ЦЕНА ЗАКРЫТИЯ AAPL')
ax2.plot(aapl['tsi'], ширина линии = 2, цвет = 'оранжевый', метка = 'ЛИНИЯ TSI')
ax2.plot(aapl['signal_line'], ширина линии = 2, цвет = '#FF006E', метка= 'СИГНАЛЬНАЯ ЛИНИЯ')
ax2.set_title('AAPL TSI 25,13,12')
ax2.legend()
plt.show()

# СТРАТЕГИЯ ИНДЕКСА ИСТИННОЙ СИЛЫ

определение реализации_tsi_strategy(цены, tsi, signal_line):
buy_price = []
sell_price = []
tsi_signal = []
signal = 0

для i в диапазоне (len(цены)):
если tsi[i-1] <signal_line[i-1] и tsi[i] > signal_line[i]:
если сигнал != 1:
buy_price.append(цены [i])
sell_price.append(np.nan)
сигнал= 1
tsi_signal.append(signal)
else:
buy_price.append(np.nan)
sell_price.append(np.nan)
tsi_signal.append(0)
если tsi[i-1] > signal_line[i-1] и tsi[i] < signal_line[i]:
если сигнал!= -1:
buy_price.append(np.nan)
sell_price.добавить (цены [i])
сигнал = -1
tsi_signal.добавить (сигнал)
еще:
buy_price.добавить(np.nan)
sell_price.добавить(np.nan)
tsi_signal.добавить(0)
еще:
buy_price.добавить(np.nan)
sell_price.добавить(np.nan)
tsi_signal.добавить (0)

возврат buy_price, sell_price, tsi_signal

buy_price, sell_price, tsi_signal = implement_tsi_strategy(aapl['close'], aapl['tsi'], aapl['signal_line'])

# ГРАФИК ТОРГОВЫХ СИГНАЛОВ ИНДЕКСА ИСТИННОЙ СИЛЫ

ax1 = plt.subplot2grid((11,1), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((11,1), (6,0), rowspan = 5, colspan = 1)
ax1.plot(aapl ['close'], linewidth = 2)
ax1.график (aapl.index, buy_price, marker = '^', markersize = 12, color = 'green', linewidth = 0, label = 'СИГНАЛ НА ПОКУПКУ')
ax1.график (aapl.index, sell_price, marker = 'v', markersize = 12, color = 'r', linewidth = 0, label = 'СИГНАЛ НА ПРОДАЖУ')
ax1.legend()
ax1.set_title('ТОРГОВЫЕ СИГНАЛЫ AAPL TSI')
ax2.plot(aapl['tsi'], linewidth = 2, color = 'orange', label = 'ЛИНИЯ TSI')
ax2.график (aapl['signal_line'], ширина линии = 2, цвет = '#FF006E', метка = 'СИГНАЛЬНАЯ ЛИНИЯ')
ax2.set_title('AAPL TSI 25,13,12')
ax2.legend()
plt.show()

# ПОЗИЦИЯ ПО АКЦИЯМ

позиция = []
для i в диапазоне (len(tsi_signal)):
если tsi_signal[i]> 1:
position.append(0)
иначе:
position.append(1)

для i в диапазоне (len(aapl['close'])):
если tsi_signal[i] == 1:
позиция [i] = 1
, если tsi_signal[i] == -1:
позиция [i] = 0
, иначе:
позиция [i] = позиция [i-1]

close_price = aapl['close']
tsi = aapl['tsi']
signal_line = aapl['signal_line']
tsi_signal = pd.DataFrame(tsi_signal).rename(столбцы = {0:'tsi_signal'}).set_index(aapl.index)
position = pd.DataFrame(позиция).переименовать(столбцы = {0:'tsi_position'}).set_index(aapl.index)

фреймы = [close_price, tsi, signal_line, tsi_signal, position]
strategy = pd.concat(фреймы, соединение = 'inner', ось = 1)

стратегия
стратегия[12:17]

# ТЕСТИРОВАНИЕ

aapl_ret = pd.DataFrame(np.diff(aapl['close'])).переименовать(столбцы = {0:'returns'})
tsi_strategy_ret = []

для i в диапазоне (len(aapl_ret)):
возвращает = aapl_ret['возвращает'][i]* стратегия['tsi_position'][i]
tsi_strategy_ret.append(возвращает)

tsi_strategy_ret_df = pd.DataFrame(tsi_strategy_ret).rename(столбцы = {0:'tsi_returns'})
investment_value = 100000
number_of_stocks = floor(investment_value/aapl['close'][0])
tsi_investment_ret = []

для i в диапазоне(len(tsi_strategy_ret_df['tsi_returns'])):
возвращает = число_из_стоков * tsi_strategy_ret_df['tsi_returns'][i]
tsi_investment_ret.append(возвращает)

tsi_investment_ret_df = pd.DataFrame(tsi_investment_ret).rename(столбцы = {0:'investment_returns'})
total_investment_ret = round(сумма (tsi_investment_ret_df['investment_returns']), 2)
profit_percentage = floor((total_investment_ret/ investment_value)*100)
print(cl('Прибыль, полученная от стратегии tsiинвестировав 100 тысяч долларов в AAPL: {}'.format(total_investment_ret), attrs = ['bold']))
print(cl('Процент прибыли от стратегии tsi: {}%'.format(profit_percentage), attrs = ['bold']))

# СРАВНЕНИЕ SPY ETF

определение get_benchmark(start_date, investment_value):
spy = get_historical_data('SPY', start_date)['close']
benchmark = pd.DataFrame(np.diff(spy)).rename(столбцы = {0:'benchmark_returns'})

investment_value = investment_value
number_of_stocks = floor(investment_value / spy[-1])
benchmark_investment_ret = []

для i в диапазоне (len(benchmark['benchmark_returns'])):
returns = number_of_stocks*benchmark['benchmark_returns'][i]
benchmark_investment_ret.append(возвращает)

benchmark_investment_ret_df = pd.DataFrame(benchmark_investment_ret).rename(столбцы = {0:'investment_returns'})
возвращает benchmark_investment_ret_df

benchmark = get_benchmark('2020-01-01', 100000)
investment_value = 100000
total_benchmark_investment_ret = round(сумма (benchmark['investment_returns']), 2)
benchmark_profit_percentage = floor((total_benchmark_investment_ret / investment_value)* 100)
print(cl('Benchmark прибыль от инвестирования $100 тыс.: {}'.format(total_benchmark_investment_ret), attrs = ['bold']))
print(cl('Процент прибыли контрольного показателя: {}%'.format(benchmark_profit_percentage), attrs = ['bold']))
print(cl('Прибыль стратегии TSI на {}% выше, чем прибыль контрольного показателя'.format(profit_percentage - benchmark_profit_percentage), attrs = ['bold']))

Источник