Александр Румянцев
Александр Румянцев личный блог
25 июля 2018, 16:17

Простой бэктестинг Rate-of-Change (ROC) на Python

Данная статья продолжает цикл анализа простых стратегий со стандартными индикаторами. Тестируем стратегии в Quantopian, а пишем на Python. В этот раз мы сравним индикатор Rate-of-Change (ROC) и популярное пересечение скользящих средних SMA(50) и SMA(200).

Дополнительно рассмотрим подход быстрого получения доходности и просадки простых стратегий в блокноте Jupyter.

Индикатор ROC показывает процент изменения текущей цены относительно  прошлого значения. Параметр индикатора — кол-во дней, между которыми сравниваем цены. Формула:

ROC(200)=(\frac{close}{close[-200]}-1)*100

Значение индикатора находится вокруг нуля.

✊Купи и держи по ROC(200)

Проверять будем на SPY, но помним, что все активы ведут себя по разному. Условия:

  • Период: 2004-2018.
  • Время сделки: за 1 час до закрытия рынка.
  • Капитал: $100K.
  • Покупка, когда ROC(200) >= 0.
  • Продажа, когда ROC(200) < 0.

Код условия на Quantopian:

# получаем цены и рассчитываем ROC(200)
price_hist = data.history(context.asset, 'close', 400, '1d')
roc = talib.ROC(price_hist, timeperiod=200)

# сигнал на значении выше нуля
allow = roc[-1] >= 0

# ...

if data.can_trade(context.asset):
    if allow:
        # покупаем актив на 100% портфеля, если разрешено
        order_target_percent(context.asset, 1.)
    else:
        # закрываем позицию при запрете
        order_target_percent(context.asset, 0.)

Результаты ROC(200) и сравнение с пересечением SMA(50) и SMA(200):

Простой бэктестинг Rate-of-Change (ROC) на Python

С 2004 год SPY вырос на +230% имея просадку в 2008 году около -55%. Рядом с этим показателем только пересечение SMA(50) и SMA(200) с меньшей просадкой. ROC(200) оказался даже хуже пересечения цены и SMA(200), показав чуть меньшее количество сделок за весь период. Внизу показан результат сглаженного ROC по формуле из этой статьи, который показал наихудший результат.

Как получить результаты без бэктеста?

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

Получение доходности

Получая итоговую доходность для серии pandas, мы проходим следующие шаги:

  1. Получаем ежедневную доходность chg=prices/prices.shift(1).
  2. Устанавливаем первое значение chg.iloc[0]=1.
  3. При необходимости применяем фильтр и смещаем условия на один день (сделка проходит после получения сигнала)  sma200=chg[(df.close>sma200).shift(1)]. Это важно запомнить, чтобы не заглядывать в будущее.
  4. Считаем доходность перемножив все значения result=np.prod(sma200) .

Код есть в telegram-канале: @quantiki.

 

 

Получение просадки

Получить максимальную просадку можно так:

  1. Получаем ежедневную доходность chg=prices/prices.shift(1).
  2. Получаем доходность на каждый день
    series.rolling(total, min_periods=1).apply(np.prod).
  3. Получаем абсолютный максимум на каждый день
    series.rolling(total, min_periods=1).max().
  4. Получаем просадку на каждый день относительно последнего максимума series/rolling_max — 1.0.
  5. Получаем максимальную просадку на каждый день daily_drawdown.rolling(total, min_periods=1).min().

В итоге имеем следующий код для расчёта простых стратегий и их просадки:
Код на Quantrum.me

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

Простой бэктестинг Rate-of-Change (ROC) на Python

  • bench — бенчмарк, результат удержания актива в течение всего времени.
  • * dd — максимальная просадка при каждом условии.
  • roc200 — удержание при ROC(200) больше нуля.
  • roc200s — использование сглаженного ROC(200).
  • s200 — пересечение цены и SMA(200).
  • s50x200 — пересечение SMA(50) и SMA(200).

Сравнив результаты с тестами на Quantopian видна разница, которой можно принебречь для принятия первичных решений. В некоторых случаях разница в доли процентов. Высока вероятность, что расхождение связано со временем ребалансировки стратегий (за 1 час до закрытия рынка). Мы же делаем расчёт по цене закрытия.

Вывод

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

В следующий раз мы ещё немного помучаем ROC. Проверим доходность, используя силу тренда, пересечение разных периодов ROC и создадим индикатор Know Sure Thing (KST), созданный Мартином Прингом на основе ROC.

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

Александр Румянцев
Автор на Quantrum.me
Telegram-канал: @quantiki

Интересуетесь алготрейдингом на Python? Присоединяйтесь к команде.

2 Комментария

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн