Volatility indicators helps us identify if the market is trending or not. The indicator we want to expose today is the Choppiness Index (CHOP).
Choppiness Index is an indicator designed to determine if the market is trading sideways. It is a metric to define the market trendiness only. A higher value means more choppiness, while lower values indicate directional trending.
The choppiness index was created by Australian E.W. Dreiss.
100 * LOG10( SUM(ATR(1), n) / ( MaxHi(n) - MinLo(n) ) ) / LOG10(n) n = User defined period length. LOG10(n) = base-10 LOG of n ATR(1) = Average True Range (Period of 1) SUM(ATR(1), n) = Sum of the Average True Range over past n bars MaxHi(n) = The highest high over past n bars
Let’s combine the choppiness index with the ema crossover strategy we created before. We’ll use the moving averages to determine the trend (7 cross over 25) and then verify if we are trending (choppiness index below 45).
if ema 7 is above ema25 AND candle before was below AND CHOP < 45 AND volume > 10 units AND candle open > 130 units (units will be in your base pair) then BUY if ema 7 is below ema25 AND candle before was above OR Profit = 15% OR Profit = -10 then SELL
How does it look like
Implementing in freqtrade
We’ll need to use qtpylib which contains the choppiness indicator.
Let’s start by copying the sample_strategy.py into another file. Change directories into your freqtrade user_data/strategy/ folder.
$ cp sample_strategy.py chop.py
Open the file and let’s modify it
- The libraries should already be imported, but just in case, make sure that this line is at the top of the strategy file:
import freqtrade.vendor.qtpylib.indicators as qtpylib
- Change the strategy class name:
- Modify roi and stoploss.
- Choose your ticker interval.
- Change use_sell_signal to True:
use_sell_signal = True
- Create the indicator in def populate_indicators function:
dataframe['chop']= qtpylib.chopiness(dataframe, 14)
dataframe['ema7'] = ta.EMA(dataframe, timeperiod=7)
dataframe['ema25'] = ta.EMA(dataframe, timeperiod=25)
- Delete unused indicators in the def populate_indicators function.
- Create the conditions on def populate_buy_trend and def populate_sell_trend.
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe['chop'] < 45) & (dataframe['ema7'] > dataframe['ema25']) & (dataframe['ema7'].shift(1) <= dataframe['ema25'].shift(1)) & ((dataframe['volume'] * dataframe['high']) > 10) & (dataframe['open']>0.00000130) ), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( ( (dataframe['ema7'] < dataframe['ema25']) & (dataframe['ema7'].shift(1) >= dataframe['ema25'].shift(1)) ) ), 'sell'] = 1 return dataframe
As always, feel free to backtest and modify the strategy to obtain better results.