Торговая стратегия с коэффициентом отклонения цены

Выделите

  • Сложность: ★ ☆☆☆☆
  • Определение длинных или коротких позиций по акциям с коэффициентом отклонения цены.
  • Эта статья переработана из Price Deviation Ratio Trading Strategy от TQuant Lab.

Предисловие

Коэффициент отклонения цены — это распространенный технический индикатор, который сравнивает текущую цену акций с N-дневной скользящей средней ценой, отражая, является ли текущая цена относительно высокой или низкой по сравнению с ее историческими значениями. Как правило, когда цена акции постоянно превышает скользящую среднюю цену, это называется «положительным отклонением». И наоборот, это называется «отрицательным отклонением», когда оно постоянно падает ниже скользящей средней цены». Поэтому, когда положительное или отрицательное отклонение расширяется, оно интерпретируется как устойчивое состояние перекупленности или перепроданности на рынке, служащее основой для принятия решений о входе и выходе. Тем не менее, использование только коэффициента отклонения цены может генерировать слишком много торговых сигналов. Следовательно, мы включаем самые высокие и самые низкие цены за последние N дней в качестве второго фильтра. Фактическая стратегия выглядит следующим образом:

Торговая стратегия

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

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

Требуемая среда редактирования и модуль

В этой статье используется MacOS и Jupyter в качестве редактора.import os
import pandas as pd
import numpy as np
import tejapi
import matplotlib.pyplot as plt

Импорт данных

Период тестирования на истории — с 02.07.2005 по 02.07.2023, и в качестве примера мы возьмем TSMC(2330).os.environ[‘TEJAPI_BASE’] = ‘https://api.tej.com.tw’
os.environ[‘TEJAPI_KEY’] = ‘your_key’
os.environ[‘mdate’] = ‘20050702 20230702’
os.environ[‘ticker’] = ‘2330’

!zipline ingest -b tquant

Импорт модулей

from zipline.api import (set_slippage,
set_commission,
set_benchmark,
attach_pipeline,
symbol,
pipeline_output,
record,
order,
order_target
)
from zipline.pipeline.filters import StaticSids
from zipline.finance import slippage, commission
from zipline import run_algorithm
from zipline.pipeline import CustomFactor, Pipeline
from zipline.pipeline.data import EquityPricing
from zipline.pipeline.factors import ExponentialWeightedMovingAverage

Создание функции конвейера

Pipeline() позволяет пользователям быстро обрабатывать данные, связанные с торговлей несколькими активами. В сегодняшней статье мы используем его для обработки:

  • EMA цены за последние 7 дней
  • Самая высокая цена за последние 7 дней (пользовательский фактор: NdaysMaxHigh)
  • Самая низкая цена за последние 7 дней(пользовательский фактор: NdaysMinLow)
  • Текущая цена закрытия

def make_pipeline():
ema = ExponentialWeightedMovingAverage(inputs = [EquityPricing.close],window_length = 7,decay_rate = 1/7)
high = NdaysMaxHigh(inputs = [EquityPricing.close], window_length = 8) # window_length 設定為 8,因為 factor 會包含當日價格。
low = NdaysMinLow(inputs = [EquityPricing.close], window_length = 8)
close = EquityPricing.close.latest
return Pipeline(
columns = {
’ema’:ema,
‘highesthigh’:high,
‘lowestlow’:low,
‘latest’:close
}
)
class NdaysMaxHigh(CustomFactor):
def compute(self, today, assets, out, data):
out[:] = np.nanmax(data[:-2], axis=0)
class NdaysMinLow(CustomFactor):
def compute(self, today, assets, out, data):
out[:] = np.nanmin(data[:-2], axis=0)

Создание функции инициализации

Initialize() позволяет пользователям настроить торговую среду в начале периода тестирования на истории. В этой статье мы настроим:

  • Проскальзывание
  • Комиссия
  • Установите доходность покупки и владения TSMC в качестве ориентира.
  • Прикрепите функцию Pipline() к тестированию на истории.

def initialize(context):
set_slippage(slippage.VolumeShareSlippage())
set_commission(commission.PerShare(cost=0.00285))
set_benchmark(symbol(‘2330’))
attach_pipeline(make_pipeline(), ‘mystrategy’)

Создание функции Handle_data

handle_data() используется для ежедневной обработки данных и совершения заказов.

  • Условие 1: Когда текущая цена закрытия больше, чем самая высокая цена за последние 7 дней, а смещение больше 0, мы рассматриваем это как сигнал на продажу.
  • Условие 2: Когда текущая цена закрытия ниже самой низкой цены за последние 7 дней, а смещение меньше 0, мы рассматриваем это как сигнал на покупку.

def handle_data(context, data):

pipe = pipeline_output(‘mystrategy’)

for i in pipe.index:
ema = pipe.loc[i, ’ema’]
highesthigh = pipe.loc[i, ‘highesthigh’]
lowestlow = pipe.loc[i, ‘lowestlow’]
close = pipe.loc[i, ‘latest’]
bias = close — ema
residual_position = context.portfolio.positions[i].amount # 當日該資產的股數
condition1 = (close > highesthigh) and (bias > 0) and (residual_position > 0) # 賣出訊號
condition2 = (close < lowestlow) and (bias < 0) # 買入訊號

record( # 用以紀錄以下資訊至最終產出的 result 表格中
con1 = condition1,
con2 = condition2,
price = close,
ema = ema,
bias = bias,
highesthigh = highesthigh,
lowestlow = lowestlow
)

if condition1:
order_target(i, 0)
elif condition2:
order(i, 10)
else:
pass

Создание функции анализа

Здесь мы применяем matplotlib.pyplot для визуализации торговых сигналов и стоимости портфеля.def analyze(context, perf):
fig = plt.figure()
ax1 = fig.add_subplot(211)
perf.portfolio_value.plot(ax=ax1)
ax1.set_ylabel(«Portfolio value (NTD)»)
ax2 = fig.add_subplot(212)
ax2.set_ylabel(«Price (NTD)»)
perf.price.plot(ax=ax2)
ax2.plot( # 繪製買入訊號
perf.index[perf.con2],
perf.loc[perf.con2, ‘price’],
‘^’,
markersize=5,
color=’red’
)
ax2.plot( # 繪製賣出訊號
perf.index[perf.con1],
perf.loc[perf.con1, ‘price’],
‘v’,
markersize=5,
color=’green’
)
plt.legend(loc=0)
plt.gcf().set_size_inches(18,8)
plt.show()

Алгоритмы запуска

Мы используем run_algorithm() для реализации нашей стратегии. Период тестирования на истории установлен в период с 06.01.2015 по 25.11.2022. Мы используем пакет данных tquant. Мы предполагаем, что начальная база капитала составляет 10 000. Вывод run_algorithm(), который является результатомs, содержит информацию о ежедневных показателях и торговых поступлениях.
results = run_algorithm(start = pd.Timestamp(‘20150106′, tz=’UTC’),
end = pd.Timestamp(‘20221125′, tz=’UTC’),
initialize=initialize,
bundle=’tquant’,
analyze=analyze,
capital_base=1e4,
handle_data = handle_data
)

Стоимость портфеля и время торговли
Trading record
Торговый рекорд

Анализ производительности

Затем мы использовали модуль Pyfolio , входящий в комплект поставки TQuant Lab, для анализа эффективности стратегии и рисков. Во-первых, мы используем extract_rets_pos_txn_from_zipline() для расчета доходности, позиций и торговых записей.import pyfolio as pf
returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(results)

Ежедневная доходность

Расчет ежедневной доходности портфеля.

Ежедневная доходность портфеля

Удержание позиций

  • Капитал(0 [2330]): TSMC
  • Наличные
Рекорд удержания позиции

Запись транзакции

  • sid: индекс
  • symbol: тикерный символ
  • Цена: цена покупки/продажи
  • order_id: номер заказа
  • amount: сумма сделки
  • COMMISSION: Стоимость комиссии
  • DT: Дата торгов
  • txn_dollar: объем торгов долларом
Торговый рекорд

Составление таблицы производительности

С помощью show_perf_stats() можно легко продемонстрировать таблицу анализа производительности и рисков.import pyfolio as pf
pf.plotting.show_perf_stats(
returns,
benchmark_rets,
positions=positions,
transactions=transactions)

Построение графика накопленной доходности и эталонной доходности

benchmark_rets = results[‘benchmark_return’]
pf.plotting.plot_rolling_returns(returns, factor_returns=benchmark_rets)

Заключение

Стратегия, представленная на этой сессии, является одной из стратегий торговли с возвратом к среднему значению. Когда рынок перепродан (Bullish Divergence, BDI < 0), а цена закрытия выше самой высокой цены за определенный период, предполагается, что цена акции будет постепенно возвращаться к цене скользящей средней, поэтому открывается длинная позиция. И наоборот, когда цена акции перекуплена (медвежья дивергенция, BDI > 0), а цена закрытия ниже самой низкой цены за определенный период, считается, что цена акции слишком сильно выросла и имеет нисходящий тренд. В этом случае происходит закрытие длинной позиции. Однако важно отметить, что эта стратегия предполагает частую торговлю, транзакционные издержки и налоги которой могут быть сведены на нет. Поэтому рекомендуется комбинировать другие технические индикаторы для оптимизации точек входа и выхода.

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

Исходный код

https://medium.com/media/9bd66021d5330737c87aaeb6913a292d

Расширенное чтение

Ссылки по теме

Источник