Implementing Andreas Clenow Plunger Indicator in Python

I wanted to check a mean revesion model as described in this post from Andreas Clenow. For this system we need to implement a simple indicator, the Clenow Plunger indicator. The purpose of this indicator is to measure the “pain” of trend followers when the price goes against the trend.

First some imports:

import pandas as pd
import numpy as np
import talib
from talib import MA_Type
import quandl
import matplotlib.pyplot as plt
from matplotlib.finance import candlestick_ohlc
import matplotlib.dates as mdates
from matplotlib.pyplot import style
from matplotlib.dates import DateFormatter, WeekdayLocator,\
    DayLocator, MONDAY

Load the data from daily bars of ES (SP500 emini) futures from quandl:

sp500_daily = quandl.get("CHRIS/CME_ES1", 
                         start_date="2012-1-1", 
                         end_date="2014-12-30")

And define our indicator:

def EMA(closes, periods = 50):
    sma = talib.MA(closes.values, timeperiod = periods, matype = MA_Type.EMA) 
    return pd.Series(data=sma, index=closes.index)

def ClenowPlunger(ohlcDaily):
    trendUp = EMA(ohlcDaily.Close, periods = 50) >  EMA(ohlcDaily.Close, periods = 100)
    trendDown = EMA(ohlcDaily.Close, periods = 50) <  EMA(ohlcDaily.Close, periods = 100)
    twentyDayHigh = pd.rolling_max(ohlcDaily.High, 20)
    twentyDayLow = pd.rolling_min(ohlcDaily.Low, 20)
    atr = pd.Series(data=talib.ATR(ohlcDaily.High.values, ohlcDaily.Low.values, ohlcDaily.Close.values, timeperiod=50),index=ohlcDaily.index)
    plungeUp = (twentyDayHigh - ohlcDaily.Close) / atr;
    plungeDown = (ohlcDaily.Close - twentyDayLow) / atr;
    clenowPlunger = trendUp*plungeUp+trendDown*plungeDown
    return pd.DataFrame(data={'ClenowPlunger':clenowPlunger,'TrendUp':trendUp,'TrendDown':trendDown},index=clenowPlunger.index)

We will test our indicator with 2013 data for emini SP500 so that we can view if it matches the behaviour as described in the linked article:

sp500_daily['ClenowPlunger']= ClenowPlunger(sp500_daily).ClenowPlunger

sp500_2013 = sp500_daily['2013']

Let’s plot the result:

style.use('ggplot')

mondays = WeekdayLocator(MONDAY)
alldays = DayLocator()
weekFormatter = DateFormatter('%b %d')
dayFormatter = DateFormatter('%d')
    
fig = plt.figure()
ax1 = fig.add_subplot(211)
sp500_2013['Date']= mdates.date2num(sp500_2013.index.to_pydatetime())
sp500_candlestick = [tuple(x) for x in sp500_2013[['Date', 'Open', 'High', 'Low', 'Close']].to_records(index=False)]
candlestick_ohlc(ax1, sp500_candlestick)  
ax1.set_ylabel('ES Futures')
ax1.xaxis.set_major_locator(mondays)
ax1.xaxis.set_minor_locator(alldays)
ax1.xaxis.set_major_formatter(weekFormatter)
ax1.xaxis_date()
ax1.autoscale_view()
plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')

ax2 = fig.add_subplot(212)
ax2.set_ylabel('Clenow Plunger')
sp500_2013['ClenowPlunger'].plot(ax=ax2)