Golden cross / Death cross strategy – Is this strategy profitable or not? - Repost (Patreon)
Downloads
Missing 1 file, as this post has not yet been imported.
Content
Intro
This is the blog post that is complementary to the video where I will be investigating a very famous trading strategy and that is the golden cross / Death cross strategy.
This strategy uses the 50 simple moving average and the 200 simple moving average.
Strategy
If the 50 SMA crosses above the 200 SMA this is considered a golden cross, also known as a bull market
When the 50 crosses below the 200 then it is considered a death cross and known as a bear market
This is a very simple strategy and I am going to test if this strategy is also good for trading crypto pairs with the help of a trading bot.
Stoploss and takeprofit
Besides the entry and exit signals of the strategy based on the indicators, there are also stoploss and takeprofit points that can be used.
These stoploss and takeprofit levels are later on determined by the hyperopt functionality of the bot and are percentage based exit levels.
Pseudocode
In pseudocode the strategy looks like this
This code should be programmed into easy to understand python code which is also compatible with the trading bot.
Initial backtest results
After backtesting and writing down all the backtest information in a sheet I have the following results
With the sma 50 / 200 crossover strategy it seems that the 4 hour, 1 hour and 30 minutes time frame performed way better than the golden and death cross on the well known daily timeframe
You can see that the hourly time frame has the best results overall with a whopping profit of more than 6800 percent, which is remarkable
Let’s see if this performance can be improved by finding better take profit and stop loss levels and maybe even better crossover sma’s
To find this out I will be using the Hyperparameter optimisation functionality of the bot.
Hyperparameter optimisation
Comparing the original hourly profit chart with the hyperopted profit chart you can clearly see that the hyperopt chart is much more smooth.
And also the drawdown period is not the same as the original hourly profit chart.
So therefore I think that because of these take profit points the chart is much more smooth and less risky than just using the death cross for your exit signal
In this case it is a tradeoff between your risk appetite and the urge to attain huge trading profits…
Conclusions
Comparing the original hourly profit chart with the hyperopted profit chart you can clearly see that the hyperopt chart is much more smooth.
And also the drawdown period is not the same as the original hourly profit chart.
So therefore I think that because of these take profit points the chart is much more smooth and less risky than just using the death cross for your exit signal
In this case it is a tradeoff between your risk appetite and the urge to attain huge trading profits…
So The conclusions of my analysis of this strategy are
Best timeframe for the golden cross / death cross strategy is the 1 hour timeframe
Adjusting the sma’s to a 53 and 201 improved performance by 8% and with a 53 / 203 sma pair it increased by 20%
But not much additional risks are added with this better performance
So Therefore I will use the 53 / 203 sma combination for further comparison
If you started with 1000 dollar a couple of years ago with these indicators
you now could have potentially slightly under 84.000 dollar
Thats a Profit of more than 8200 percent.
However you risk a drawdown from the highest profit point of around 548 percent and have a risk or ruin of 126%
The point where a drawdown starts is dependent on market circumstances and is very unpredictable
You should be very aware of this when starting to trade with a bot.
If you do not like risks, then use take profit and stoploss points.
The points that were given by the hyperopt engine caused the amount of winning trades to increase from 36% to 62%
However you lose the chance of getting huge profits with a relative small amount of money and have moderate gains
Strategy League
So after I entered both results in my overall strategy comparison I get the following:
The strategy code
# --- Do not remove these libs ---
import numpy as np # noqa
import pandas as pd # noqa
from functools import reduce
from pandas import DataFrame
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,IStrategy, IntParameter)
# --- Add your lib to import here ---
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
# --- Generic strategy settings ---
class SmaCrossover(IStrategy):
INTERFACE_VERSION = 2
# Determine timeframe and # of candles before strategysignals becomes valid
timeframe = '1d'
# Determine roi take profit and stop loss points
minimal_roi = {"0": 1000.00}
stoploss = -1000.00
trailing_stop = False
use_sell_signal = True
sell_profit_only = False
sell_profit_offset = 0.0
ignore_roi_if_buy_signal = False
# --- Plotting ---
# Use this section if you want to plot the indicators on a chart after backtesting
plot_config = {
'main_plot': {
# Create sma50 and sma200 line
'quick_sma': {'color': 'blue'},
'slow_sma': {'color': 'red'},
},
# 'subplots': {
# # Create subplot MACD
# "MACD": {
# 'macd': {'color': 'blue', 'fill_to': 'macdsignal'},
# 'macdsignal': {'color': 'orange'},
# 'macdhist': {'color': 'green', 'type': 'bar', 'plotly': {'opacity': 0.4}}
# },
# },
}
# --- Define spaces for the indicators ---
# Buy space - UNCOMMENT THIS FOR HYPEROPTING
# quick_sma = IntParameter(35, 65, default=50, space="buy")
# slow_sma = IntParameter(185, 215, default=200, space="buy")
# --- Used indicators of strategy code ----
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# SMA's for buying - UNCOMMENT THIS FOR HYPEROPTING
# for val in self.quick_sma.range:
# dataframe[f'quick_sma_{val}'] = ta.SMA(dataframe, timeperiod=val)
# for val in self.slow_sma.range:
# dataframe[f'slow_sma_{val}'] = ta.SMA(dataframe, timeperiod=val)
# Polulate SMA indicators - COMMENT THIS SECTION OUT WHEN HYPEROPTING
dataframe['quick_sma'] = ta.SMA(dataframe, timeperiod=50)
dataframe['slow_sma'] = ta.SMA(dataframe, timeperiod=200)
return dataframe
# --- Buy settings ---
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# UNCOMMENT THIS FOR HYPEROPTING
# conditions = []
# conditions.append(qtpylib.crossed_above(
# dataframe[f'quick_sma_{self.quick_sma.value}'],
# dataframe[f'slow_sma_{self.slow_sma.value}']
# ))
# if conditions:
# dataframe.loc[
# reduce(lambda x, y: x & y, conditions),
# 'buy'] = 1
# Enter the conditions for buying - COMMENT THIS SECTION OUT WHEN HYPEROPTING
dataframe.loc[
(
# Buy when SMA 50 crosses above SMA 200
(qtpylib.crossed_above(dataframe['quick_sma'], dataframe['slow_sma']))
),
'buy'] = 1
return dataframe
# --- long settings ---
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# UNCOMMENT THIS FOR HYPEROPTING
# conditions = []
# conditions.append(qtpylib.crossed_below(
# dataframe[f'quick_sma_{self.quick_sma.value}'],
# dataframe[f'slow_sma_{self.slow_sma.value}']
# ))
# if conditions:
# dataframe.loc[
# reduce(lambda x, y: x & y, conditions),
# 'sell'] = 1
# Enter the conditions for selling - COMMENT THIS SECTION OUT WHEN HYPEROPTING
dataframe.loc[
(
# Buy when SMA 50 crosses above SMA 200
(qtpylib.crossed_below(dataframe['quick_sma'], dataframe['slow_sma']))
),
'sell'] = 1
return dataframe
The hyperopt code
# --- Do not remove these libs ---
import numpy as np # noqa
import pandas as pd # noqa
from functools import reduce
from pandas import DataFrame
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,IStrategy, IntParameter)
# --- Add your lib to import here ---
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
# --- Generic strategy settings ---
class SmaCrossoverHopt(IStrategy):
INTERFACE_VERSION = 2
# Determine timeframe and # of candles before strategysignals becomes valid
timeframe = '1d'
# Determine roi take profit and stop loss points
minimal_roi = {"0": 1000.00}
stoploss = -1000.00
trailing_stop = False
use_sell_signal = True
sell_profit_only = False
sell_profit_offset = 0.0
ignore_roi_if_buy_signal = False
# --- Plotting ---
# Use this section if you want to plot the indicators on a chart after backtesting
plot_config = {
'main_plot': {
# Create sma50 and sma200 line
'quick_sma': {'color': 'blue'},
'slow_sma': {'color': 'red'},
},
# 'subplots': {
# # Create subplot MACD
# "MACD": {
# 'macd': {'color': 'blue', 'fill_to': 'macdsignal'},
# 'macdsignal': {'color': 'orange'},
# 'macdhist': {'color': 'green', 'type': 'bar', 'plotly': {'opacity': 0.4}}
# },
# },
}
# --- Define spaces for the indicators ---
# Buy space - UNCOMMENT THIS FOR HYPEROPTING
quick_sma = IntParameter(45, 55, default=50, space="buy")
slow_sma = IntParameter(195, 205, default=200, space="buy")
# --- Used indicators of strategy code ----
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# SMA's for buying - UNCOMMENT THIS FOR HYPEROPTING
for val in self.quick_sma.range:
dataframe[f'quick_sma_{val}'] = ta.SMA(dataframe, timeperiod=val)
for val in self.slow_sma.range:
dataframe[f'slow_sma_{val}'] = ta.SMA(dataframe, timeperiod=val)
# Polulate SMA indicators - COMMENT THIS SECTION OUT WHEN HYPEROPTING
# dataframe['quick_sma'] = ta.SMA(dataframe, timeperiod=50)
# dataframe['slow_sma'] = ta.SMA(dataframe, timeperiod=200)
return dataframe
# --- Buy settings ---
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# UNCOMMENT THIS FOR HYPEROPTING
conditions = []
conditions.append(qtpylib.crossed_above(
dataframe[f'quick_sma_{self.quick_sma.value}'],
dataframe[f'slow_sma_{self.slow_sma.value}']
))
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'buy'] = 1
# Enter the conditions for buying - COMMENT THIS SECTION OUT WHEN HYPEROPTING
# dataframe.loc[
# (
# # Buy when SMA 50 crosses above SMA 200
# (qtpylib.crossed_above(dataframe['quick_sma'], dataframe['slow_sma']))
# ),
# 'buy'] = 1
return dataframe
# --- long settings ---
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# UNCOMMENT THIS FOR HYPEROPTING
conditions = []
conditions.append(qtpylib.crossed_below(
dataframe[f'quick_sma_{self.quick_sma.value}'],
dataframe[f'slow_sma_{self.slow_sma.value}']
))
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'sell'] = 1
# Enter the conditions for selling - COMMENT THIS SECTION OUT WHEN HYPEROPTING
# dataframe.loc[
# (
# # Buy when SMA 50 crosses above SMA 200
# (qtpylib.crossed_below(dataframe['quick_sma'], dataframe['slow_sma']))
# ),
# 'sell'] = 1
return dataframe
The hyperopt json results
{
"strategy_name": "SmaCrossoverHopt",
"params": {
"trailing": {
"trailing_stop": false,
"trailing_stop_positive": null,
"trailing_stop_positive_offset": 0.0,
"trailing_only_offset_is_reached": false
},
"buy": {
"quick_sma": 53,
"slow_sma": 203,
},
"sell": {},
"protection": {},
"roi": {
"0": 0.31,
"470": 0.183,
"1145": 0.08,
"2580": 0
},
"stoploss": {
"stoploss": -0.346
}
},
"ft_stratparam_v": 1,
"export_time": "2022-01-06 08:10:47.100043+00:00"
}