MACD and CCI Entry and Exit Rules with Hyperparameter Search
Summary
This Freqtrade strategy combines MACD direction with the Commodity Channel Index (CCI) to generate long entries and exits. It enters when MACD is above its signal line and CCI is at or below a tunable buy threshold; it exits when MACD is below its signal line and CCI is at or above a tunable sell threshold. Both conditions also require nonzero volume.
The strategy exposes buy and sell CCI thresholds for hyperparameter optimization, with separate search ranges on each side of zero. It also defines a five-minute timeframe, a tiered minimal-return schedule, and a stop-loss setting. These are implementation defaults rather than evidence of profitability: the supplied material includes no backtest results, market specification, or validation procedure, and optimized thresholds may not generalize beyond the data used to select them.
Key ideas
- Long entries require MACD above its signal line and CCI below the buy threshold.
- Long exits require MACD below its signal line and CCI above the sell threshold.
- The strategy excludes signals when volume is zero.
- Buy and sell CCI thresholds are exposed for hyperparameter optimization.
- The code provides risk and return settings but no performance evidence.
Tags
Full text
# MACDStrategy.py
```py
# --- Do not remove these libs ---
from freqtrade.strategy import IStrategy
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter
from pandas import DataFrame
# --------------------------------
import talib.abstract as ta
class MACDStrategy(IStrategy):
"""
author@: Gert Wohlgemuth
idea:
uptrend definition:
MACD above MACD signal
and CCI < -50
downtrend definition:
MACD below MACD signal
and CCI > 100
freqtrade hyperopt --strategy MACDStrategy --hyperopt-loss <someLossFunction> --spaces buy sell
The idea is to optimize only the CCI value.
- Buy side: CCI between -700 and 0
- Sell side: CCI between 0 and 700
"""
INTERFACE_VERSION: int = 3
# Minimal ROI designed for the strategy.
# This attribute will be overridden if the config file contains "minimal_roi"
minimal_roi = {
"60": 0.01,
"30": 0.03,
"20": 0.04,
"0": 0.05
}
# Optimal stoploss designed for the strategy
# This attribute will be overridden if the config file contains "stoploss"
stoploss = -0.3
# Optimal timeframe for the strategy
timeframe = '5m'
buy_cci = IntParameter(low=-700, high=0, default=-50, space='buy', optimize=True)
sell_cci = IntParameter(low=0, high=700, default=100, space='sell', optimize=True)
# Buy hyperspace params:
buy_params = {
"buy_cci": -48,
}
# Sell hyperspace params:
sell_params = {
"sell_cci": 687,
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
dataframe['cci'] = ta.CCI(dataframe)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the buy signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
(
(dataframe['macd'] > dataframe['macdsignal']) &
(dataframe['cci'] <= self.buy_cci.value) &
(dataframe['volume'] > 0) # Make sure Volume is not 0
),
'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the sell signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[
(
(dataframe['macd'] < dataframe['macdsignal']) &
(dataframe['cci'] >= self.sell_cci.value) &
(dataframe['volume'] > 0) # Make sure Volume is not 0
),
'exit_long'] = 1
return dataframe
```Shown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.