HiLo & MACD strategy – Is this strategy profitable or not? repost (Patreon)
Downloads
Missing 1 file, as this post has not yet been imported.
Content
Intro
Hi there and welcome to this blog series where I will be searching for the best trading strategy for cryptocurrency trading. Each strategy will be tested on its performance by trading multiple digital asset pairs over their largest possible backtest period. The result of this test is then compared with the results of earlier tested strategies.
In this post I will test the Gann Hilo activator in combination with the MACD to see if this is a successful trading combination.
At the end of this post all code will be available.
Strategy
As said earlier, I am going to test the Gann Hilo indicator in combination with the macd.
The Gann Hilo indicator is a trend following indicator that helps to define trend directions and entry signals
This indicator should preferably be used with the Gann Swing oscillator and Gann trend oscillator.
But since both these last indicators are not available in the pandas, talib or qtpylin library, I am trusting on the well known macd indicator for trend confirmations.
Instead of the usual three period highs and low average that is used on the Gann indicator
Also for starters I am going to use the 21 day average instead of the initial previous three periods highs or lows averages in this test
The buy and sell settings are very easy to understand
Buy when the Hilo activator is below the price and the macd histogram is positive
The sell signal only comes from the MACD histogram. When the histogram is below 0, then a sell signal is given.
This is a very simple strategy and I am going to test if this is also good for trading crypto pairs with the help of a trading bot.
Stoploss and takeprofit
Pseudocode
The pseudocode of this strategy is very simple and easy to turn into python code for buy and sell signals.
Buy when the close price is above the HiLo activator and MACD histogram is above zero
Ans sell when the MACD is below 0
So in this case the Hilo activator is no exit indicator
Initial backtest results
After backtesting and writing down all the backtest information in a sheet I have the following results
The best timeframe is the 1 day timeframe.
It has a backtests profit of 3207 percent which could have turned 1000 dollar into over 33000 dollar hypothetically
The drawdown is 594 percent and the possible risk of ruin is 128 percent.
I have a feeling that these results can be improved if we run this strategy through the hyperopt function and use roi and stoploss settings as well.
Hyperparameter optimisation
As you can see the hyperopt session proposed some improvements.
But these improvements did not seem to give better results overall when backtesting.
So I was wrong in my earlier thought that this could be improved.
The only improvements seemed to be the win rate and therefore the risk of ruin.
But the total profit was less and also less pairs seem to work on these settings so therefore my overall score is worse than the original settings.
I also did a second hyperopt session (which is not included in this video.
I wanted to only find the best HiLo settings to see if that could give better results
And indeed I got other Hilo settings that proved to give much better results in comparison to the hyperopt result with ROI and Stoploss.
And it gave a better profit and better risk of ruin results as well.
However less pairs seem to get profit from this strategy so only because of this it became a close second. But the Hilo Setting of 28 looks promising because it causes less unnecessary trades as you can see on these graphs.
Conclusions
So, The conclusions of my analysis of this strategy are
- Best timeframe for this Gann Hilo with MACD strategy is the one day timeframe
- The Hilo average is advised to be 21 but the 28 setting also produced good results
- Using the bot’s stoploss and takeprofit settings did not improve the performance of the strategy
- If you started with 1000 dollar a couple of years ago with these indicators
- In theory you could have potentially slightly over 33.000 dollar
- Thats a profit of 3207 %
- The winrate is 51%
- And drawdown is 594 % you should take that into consideration when using this strategy
- The risk of ruin is 128%
So after I entered the results in my overall strategy comparison I get the following:
Strategy League
This strategy is the worst performing one yet.
You still might have profits but the drawdown and risk of ruin are worrying
Also the ratio of the winning and losing pairs is one of the worst
So before you decide to trade with these indicator, please do your own research, backtest and forward test this according to your own methodology to be sure this strategy is for you.
Files
Download all files with code, backtest results and more by downloading the file below:
The strategy code
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
# --------------------------------
import talib.abstract as ta
import pandas_ta as pta
import freqtrade.vendor.qtpylib.indicators as qtpylib
class HiLo(IStrategy):
timeframe = "1d"
stoploss = -100.0
minimal_roi = {"0": 100.0}
# --- Plotting ---
# Use this section if you want to plot the indicators on a chart after backtesting
plot_config = {
'main_plot': {
# Create sma line
'hilo': {'color': 'blue'},
},
'subplots': {
# Create rsi subplot
"MACD": {
'macd': {'color': 'blue', 'fill_to': 'macdsignal'},
'macdsignal': {'color': 'orange'},
'macdhist': {'color': 'green', 'type': 'bar', 'plotly': {'opacity': 0.4}}
},
},
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Gann HiLo
highl = 21
lowl = 21
dataframe["hilo"] = pta.hilo(
high=dataframe["high"],
low=dataframe["low"],
close=dataframe["close"],
high_length=highl,
low_length=lowl,
mamode=None,
offset=None,
)[f"HILO_{highl}_{lowl}"]
# MACD
macd = ta.MACD(
dataframe,
fastperiod=12,
fastmatype=0,
slowperiod=26,
slowmatype=0,
signalperiod=9,
signalmatype=0,
)
dataframe["macd"] = macd["macd"]
dataframe["macdsignal"] = macd["macdsignal"]
dataframe["macdhist"] = macd["macdhist"]
# print(dataframe)
return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe["close"] > dataframe["hilo"])
& (dataframe["macdhist"] > 0)
),
"buy",
] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
# (dataframe["close"] < dataframe["hilo"])
(dataframe["macdhist"] < 0)
),
"sell",
] = 1
return dataframe
The hyperopt code
# --- Do not remove these libs ---
import talib.abstract as ta
import pandas_ta as pta
import numpy as np # noqa
import pandas as pd # noqa
import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
from functools import reduce
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,IStrategy, IntParameter)
class HiLoHopt(IStrategy):
timeframe = "1d"
stoploss = -100.0
minimal_roi = {"0": 100.0}
# --- Plotting ---
# Use this section if you want to plot the indicators on a chart after backtesting
plot_config = {
'main_plot': {
# Create sma line
'hilo': {'color': 'blue'},
},
'subplots': {
# Create rsi subplot
"MACD": {
'macd': {'color': 'blue', 'fill_to': 'macdsignal'},
'macdsignal': {'color': 'orange'},
'macdhist': {'color': 'green', 'type': 'bar', 'plotly': {'opacity': 0.4}}
},
},
}
# --- Define spaces for the indicators ---
hilo_range = IntParameter(3, 60, default=21, space="buy")
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Gann HiLo
for val in self.hilo_range.range:
dataframe[f"hilo_{val}"] = pta.hilo(
high=dataframe["high"],
low=dataframe["low"],
close=dataframe["close"],
high_length=val,
low_length=val,
mamode=None,
offset=None,
)[f"HILO_{val}_{val}"]
# MACD
macd = ta.MACD(
dataframe,
fastperiod=12,
fastmatype=0,
slowperiod=26,
slowmatype=0,
signalperiod=9,
signalmatype=0,
)
dataframe["macd"] = macd["macd"]
dataframe["macdsignal"] = macd["macdsignal"]
dataframe["macdhist"] = macd["macdhist"]
# print(dataframe)
return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
conditions.append(
(dataframe['close'] > dataframe[f'hilo_{self.hilo_range.value}'])
& (dataframe['macd'] > dataframe['macdsignal'])
)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'buy'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
conditions.append(
(dataframe['macd'] < dataframe['macdsignal'])
)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'sell'] = 1
return dataframe
The hyperopt json results
{
"strategy_name": "HiLoHopt",
"params": {
"trailing": {
"trailing_stop": false,
"trailing_stop_positive": null,
"trailing_stop_positive_offset": 0.0,
"trailing_only_offset_is_reached": false
},
"buy": {
"hilo_range": 34
},
"sell": {},
"protection": {},
"roi": {
"0": 0.6559999999999999,
"8856": 0.372,
"25907": 0.149,
"41106": 0
},
"stoploss": {
"stoploss": -0.313
}
},
"ft_stratparam_v": 1,
"export_time": "2022-01-14 12:02:37.092604+00:00"
}