“The Slope is Dope” – trading bot strategy. Is it profitable or not? (Patreon)
Downloads
Missing 2 files, as this post has not yet been imported.
Content

Unbeleivable profits with major potential caveats!
In this blog post I am going to take one of my older trading bot strategies that makes use of the slope or steepness of a line to determine a trade or not. I you have watched my video about this ‘Slope is dope’ strategy, then you will see some unbeleivable results. I will show you in this post how I came to these results, the assumptions I made and the thinking errors.
Subscriber help
One of my subscribers (TheDjarEl) mentioned that the way the strategy handles its 4th candle.
Literaly he says:
I found the glitch. The strategy is exploiting the way the trailing stop loss is evaluated in the backtest (the sequence on how the 4h candle plays.). You need to add the parameter –timeframe-detail 15m to the Backtest command (or less than 15m) and download the needed data. Then the performance goes to +1189% with 54% max drawdown.
So many thanks for pointing this out.
A warning though
For this specific blog post however I am going to keep the thinking error (and faulty results) for two things:
- It accompanies the video in it’s explanation and
- I want to show you how I made this mistake so that you can learn from this
I will do new tests and expect a other outcome. Then I will make a new post about these results and correct the strategy league with these.
Intro
But , as I said, In this post I will show you this older trading bot strategy and test it to see how it performs in comparison to all the earlier tested strategies.
It is a lagging strategy that was build for spot trading and only for longs since the freqtrade bot did not have the capability to go short at that time.
The idea behind this strategy is that I only enter a trade when a moving average goes upward. In these cases a moving average has a certain positive slope, or steepness. The slope of a line is a non-angular representation of the angle between the line and a horizontal line such as the x-axis. The higher the slope number here, the more parabolic the moving average goes.
To make use of an example, here I have two simple graphs. One where the slope between two points on the Moving average is low and one where the moving average is going parabolic and therefore also where the slope is much bigger.
So the idea here is to find assets where the moving average rises sharply and so indicating demand on the asset.
Now this is somewhat of an oversimplification because my strategy uses more parameters to decide trades or not. But this slope idea is the main baseline for making the decision.
Calculating a slope
To calculate the slope of a line you have to devide the rise of a point by the run of a point.
This means that you have to divide the difference between the lower and higher point on the Y-axis (which is the rise) with the difference between the two points on the X-axis (which is the run).
- so the rise is Y2 – Y1
- and the run is X2 – X1
To use the example graphs here:
- The rise is the difference on the Y-axis between point B and A
- And the run is the difference on the X-axis between point B and A
So if the rise is 4 and the run is 6, then the slope is 4 divided by 6, which is 0.666
Now if the slope is 0 then it is a flat line because Y has no inclination.
And when the slope is negative, the moving average goes down. It’s that simple.
Strategy code explaination
Let’s open the code of this strategy and see how it’s programmed:
Let’s start with the generic settings.
The initial ROI of this strategy is 0.6 which means that the strategy takes profit at 60% gains.
The stoploss is set to 0.9 which is 90% loss. This setting looks too high but I have programmed a trailing stoploss in the exit indicators so I expect to never make use of this setting.
Then the timeframe is set to the 4 hour timeframe. And we will see later if that is really the best setting for this strategy.
It is important to notice here that I also make use of a trailing stop loss, which is based on an offset. When the position has a 28% gain, which is determined by the positive offset parameter, the offset gets triggered. Then when there is a 3% loss in the price where the offset was triggered on, the bot will sell the position. In these cases there would be a theoretical 25% gain on the trade.
class slope_is_dope(IStrategy):
# Minimal ROI designed for the strategy.
minimal_roi = {
"0": 0.6
}
stoploss = -0.9
timeframe = '4h'
# Trailing stoploss
trailing_stop = True
trailing_only_offset_is_reached = True
trailing_stop_positive = 0.03
trailing_stop_positive_offset = 0.28
THe next section contains the indicators I am going to use in this strategy.
As you can read, there are more indicators than just a moving average and slope calculation.
Let’s discuss these indicators:
- The first indicator I use is a RSI which is set to a short 7 periods.
- Then there are a bunch of moving averages that each have their own function. The first one is the Market Moving Average that helps me determing the major Bull and Bear markets. You can use this as a switch if you only want to trade above the 200 MA. And beware that is the 200 MA of the specific timeframe. Then there are a slow and fast moving average. The slopes I use are determined from these MA’s. And then there is an entry MA which I will explain later.
- And I use a slope calculation section that determines the slope on the slow and fast MA.
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=7)
dataframe['marketMA'] = ta.SMA(dataframe, timeperiod=200)
dataframe['fastMA'] = ta.SMA(dataframe, timeperiod=21)
dataframe['slowMA'] = ta.SMA(dataframe, timeperiod=50)
dataframe['entryMA'] = ta.SMA(dataframe, timeperiod=3)
# Calculate slope of slowMA
# See: https://www.wikihow.com/Find-the-Slope-of-a-Line
dataframe['sy1'] = dataframe['slowMA'].shift(+11)
dataframe['sy2'] = dataframe['slowMA'].shift(+1)
sx1 = 1
sx2 = 11
dataframe['sy'] = dataframe['sy1'] - dataframe['sy1']
dataframe['sx'] = sx2 - sx1
dataframe['slow_slope'] = dataframe['sy']/dataframe['sx']
dataframe['fy1'] = dataframe['fastMA'].shift(+11)
dataframe['fy2'] = dataframe['fastMA'].shift(+1)
fx1 = 1
fx2 = 11
dataframe['fy'] = dataframe['fy2'] - dataframe['fy1']
dataframe['fx'] = fx2 - fx1
dataframe['fast_slope'] = dataframe['fy']/dataframe['fx']
# print(dataframe[['date','close', 'slow_slope','fast_slope']].tail(50))
# ==== Trailing custom stoploss indicator ====
dataframe['last_lowest'] = dataframe['low'].rolling(10).min().shift(1)
return dataframe
Now the more experienced programmers will immediately say that these calculations can be made in one line without making the dataframe unnecessarily big.
And also making use of variables for the x and y points can be more logic.
But for me this works, although it is indeed more quick and dirty looking this way. But I go for efficiency instead of beauty at the moment. It the strategy is very good, I’ll decide later to make this code look nice.
Let’s create the strategy in a Jupyter notebook and see things in action.
Eplanation of strategy using Jupyter Notebooks
First I will import the necessary functions and create a dataframe from the downloaded btc-usdt dataset.
And with the dataframe.head function you can see the first 5 entries of the dataframe.
In [2]:
# Import libraries
import pandas as pd
import pandas_ta as pta
from pandas import DataFrame
import numpy as np
# Create dataframe
dataframe = pd.read_json("./data/BTC_USDT-1d.json")
dataframe.columns=['date','open','high','low','close','volume']
dataframe['date']=(pd.to_datetime(dataframe['date'],unit='ms'))
# Show the dataframe
dataframe.head()
Out[2]:
date
open
high
low
close
volume
0
2017-08-17
4261.48
4485.39
4200.74
4285.08
795.150377
1
2017-08-18
4285.08
4371.52
3938.77
4108.37
1199.888264
2
2017-08-19
4108.37
4184.69
3850.00
4139.98
381.309763
3
2017-08-20
4120.98
4211.08
4032.62
4086.29
467.083022
4
2017-08-21
4069.13
4119.62
3911.79
4016.00
691.743060
In the following cell I will add the indicators, and I start with the RSI.
In [3]:
# Lets add the indicators, starting with the RSI
dataframe['rsi'] = pta.rsi(close=dataframe['close'], timeperiod=7)
dataframe.tail(5)
Out[3]:
date
open
high
low
close
volume
rsi
1833
2022-08-24
21529.11
21900.00
21145.00
21368.08
174383.22046
38.842500
1834
2022-08-25
21368.05
21819.88
21310.15
21559.04
169915.78301
40.904672
1835
2022-08-26
21559.04
21886.77
20107.90
20241.05
273811.61955
32.707306
1836
2022-08-27
20239.14
20402.93
19800.00
20037.60
162582.46032
31.652813
1837
2022-08-28
20037.60
20171.18
19520.00
19555.61
139307.95976
29.247083
Then I will add all the Moving averages.
In [4]:
# Let's now add all the other indicators to the dataframe
dataframe['marketMA'] = pta.sma(close=dataframe['close'], timeperiod=200)
dataframe['fastMA'] = pta.sma(close=dataframe['close'], timeperiod=21)
dataframe['slowMA'] = pta.sma(close=dataframe['close'], timeperiod=50)
dataframe['entryMA'] = pta.sma(close=dataframe['close'], timeperiod=3)
dataframe.tail(5)
Out[4]:
date
open
high
low
close
volume
rsi
marketMA
fastMA
slowMA
entryMA
1833
2022-08-24
21529.11
21900.00
21145.00
21368.08
174383.22046
38.842500
22227.052
22227.052
22227.052
22227.052
1834
2022-08-25
21368.05
21819.88
21310.15
21559.04
169915.78301
40.904672
21973.474
21973.474
21973.474
21973.474
1835
2022-08-26
21559.04
21886.77
20107.90
20241.05
273811.61955
32.707306
21612.105
21612.105
21612.105
21612.105
1836
2022-08-27
20239.14
20402.93
19800.00
20037.60
162582.46032
31.652813
21281.599
21281.599
21281.599
21281.599
1837
2022-08-28
20037.60
20171.18
19520.00
19555.61
139307.95976
29.247083
20918.040
20918.040
20918.040
20918.040
Slope calculation in the dataframe
Now that we have all the necessary indicators, it is time to calculate the slope’s of the fast and slow MA, since we are using these as the main source for our buy signal.
As you can see I calculate the slope by determining the price of the moving average on the y-axis point at a specific row with both the dataframe['sy1'] = dataframe['slowMA'].shift(+11) function. The x-axis points are just the amount of rows these points were set to.
With the dataframe['sy'] = dataframe['sy2'] - dataframe['sy1'] and dataframe['sx'] = sx2 - sx1 I calculate the difference between the points and then finally I calculate the slope by using dataframe['slow_slope'] = dataframe['sy']/dataframe['sx'].
By the way. The lookback number (+11) is arbitrary and you can set this anyway you like. I chose the the candle of 11 rows (days) ago to calculate the run. But you can also use other numbers according to your own preference or trading results.
In [7]:
# Slow MA Y-axis A point
dataframe['sy1'] = dataframe['slowMA'].shift(+11)
dataframe['sy2'] = dataframe['slowMA'].shift(+1)
sx1 = 1
sx2 = 11
dataframe['sy'] = dataframe['sy2'] - dataframe['sy1']
dataframe['sx'] = sx2 - sx1
dataframe['slow_slope'] = dataframe['sy']/dataframe['sx']
dataframe['fy1'] = dataframe['fastMA'].shift(+11)
dataframe['fy2'] = dataframe['fastMA'].shift(+1)
fx1 = 1
fx2 = 11
dataframe['fy'] = dataframe['fy2'] - dataframe['fy1']
dataframe['fx'] = fx2 - fx1
dataframe['fast_slope'] = dataframe['fy']/dataframe['fx']
dataframe[['date','close','fastMA','fy1','fy2','fy','fx','fast_slope']].tail(15)
Out[7]:
date
close
fastMA
fy1
fy2
fy
fx
fast_slope
1823
2022-08-14
24305.24
23743.971
22914.570
23575.745
661.175
10
66.1175
1824
2022-08-15
24094.82
23822.211
23045.778
23743.971
698.193
10
69.8193
1825
2022-08-16
23854.74
23912.264
23251.553
23822.211
570.658
10
57.0658
1826
2022-08-17
23342.66
23929.091
23251.729
23912.264
660.535
10
66.0535
1827
2022-08-18
23191.20
23867.211
23184.875
23929.091
744.216
10
74.4216
1828
2022-08-19
20834.39
23635.655
23188.500
23867.211
678.711
10
67.8711
1829
2022-08-20
21140.07
23354.257
23139.144
23635.655
496.511
10
49.6511
1830
2022-08-21
21515.61
23112.379
23205.217
23354.257
149.040
10
14.9040
1831
2022-08-22
21399.83
22811.994
23271.855
23112.379
-159.476
10
-15.9476
1832
2022-08-23
21529.12
22520.768
23413.444
22811.994
-601.450
10
-60.1450
1833
2022-08-24
21368.08
22227.052
23575.745
22520.768
-1054.977
10
-105.4977
1834
2022-08-25
21559.04
21973.474
23743.971
22227.052
-1516.919
10
-151.6919
1835
2022-08-26
20241.05
21612.105
23822.211
21973.474
-1848.737
10
-184.8737
1836
2022-08-27
20037.60
21281.599
23912.264
21612.105
-2300.159
10
-230.0159
1837
2022-08-28
19555.61
20918.040
23929.091
21281.599
-2647.492
10
-264.7492
As you can see here I do nothing fancy.
Just pay attention to the fast_slope column. When itis positif, then the moving average is rising and when the number is negative, it is falling.
The other slope related columns are there for reference and checks.
Trailing stop loss
Now this next line of code is something special. Here I determine a separate stop loss based on candle information. This stoploss can also act like a trailing stoploss.
What I do is simply select the last 10 candles each time there is a new dataframe entry. Then the lowest low is determined with the .min() function. This value will be used as a minimum value the close price should cross and then trigger a sell signal. The shift function puts that value in the current row of the dataframe so that it can be used for comparison with the current close and therefore as the treshold for closing the position.
# ==== Trailing custom stoploss indicator ====
dataframe['last_lowest'] = dataframe['low'].rolling(10).min().shift(1)
`
If I put this in a dataframe, then you will see what I mean.
I create a new column that determines the lowest low over the rolling 10 previous candles and then shift that value to the current row cell.
You can then see what I mean if i only show you the date, close, low and last_lowest column.
In [6]:
# ==== Trailing custom stoploss indicator ====
dataframe['last_lowest'] = dataframe['low'].rolling(10).min().shift(1)
dataframe[['date','close','low','last_lowest']].tail(15)
Out[6]:
date
close
low
last_lowest
1823
2022-08-14
24305.24
24144.00
22400.00
1824
2022-08-15
24094.82
23773.22
22586.95
1825
2022-08-16
23854.74
23671.22
22664.69
1826
2022-08-17
23342.66
23180.40
22664.69
1827
2022-08-18
23191.20
23111.04
22664.69
1828
2022-08-19
20834.39
20783.57
22664.69
1829
2022-08-20
21140.07
20761.90
20783.57
1830
2022-08-21
21515.61
21069.11
20761.90
1831
2022-08-22
21399.83
20890.18
20761.90
1832
2022-08-23
21529.12
20890.14
20761.90
1833
2022-08-24
21368.08
21145.00
20761.90
1834
2022-08-25
21559.04
21310.15
20761.90
1835
2022-08-26
20241.05
20107.90
20761.90
1836
2022-08-27
20037.60
19800.00
20107.90
1837
2022-08-28
19555.61
19520.00
19800.00
To be clear. See row 1829. There the lowest low was determined at a price of 20791.90. This will be detected by the lowest low over those 10 periods. Then this value is used in the last_lowest column from row 1830 to 1836. There a new lowest low has been detected anduntil a new lowest low is detected over the last 10 candles.
Now if the close price would get below that low (at rown 1835 for example) then the bot would close the position.
Let’s continue with the code.
Here is a plotting section here that can be used to plot these moving averages and RSI on a chart. I was doing a lot of plotting back then but slowly starting to move over to Jupyter notebooks for that.
plot_config = {
"main_plot": {
# Configuration for main plot indicators.
"fastMA": {"color": "red"},
"slowMA": {"color": "blue"},
},
"subplots": {
# Additional subplots
"rsi": {"rsi": {"color": "blue"}},
"fast_slope": {"fast_slope": {"color": "red"}, "slow_slope": {"color": "blue"}},
},
}
Strategy rules
Let’s continue with the actual rules for this strategy.
In the cell below you can see here that I have a bunch of code that determine the trade signal.
To begin with the commented out options. These were the options that I tested to see if I got better results but they did not. However I left them in the code for future reference. Maybe it can help you also to try out some alternative options for your entry signals.
The real signals come from the following parameters:
- First of all the market should be bullish, which is determined by the 200 MA on the used timeframe.
- The fast and slow MA slope should both be positive for entering a position.
- The close price should be above highest candle of 11 days ago. Optionally here I had a 3 day average of 11 days ago but this option was also fine.
And then some confirmation settings:
- The RSI should be above 55 as a momentum indicator
- And finally the fast MA should be above the slow MA also
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
# Only enter when market is bullish (this is a choice)
(
(dataframe['close'] > dataframe['marketMA']) &
# Only trade when the fast slope is above 0
(dataframe['fast_slope'] > 0) &
# Only trade when the slow slope is above 0
(dataframe['slow_slope'] > 0) &
# Only buy when the close price is higher than the 3day average of ten periods ago
#(dataframe['close'] > dataframe['entryMA'].shift(+11)) &
# Or only buy when the close price is higher than the close price of 3 days ago (this is a choice)
(dataframe['close'] > dataframe['close'].shift(+11)) &
# Only enter trades when the RSI is higher than 55
(dataframe['rsi'] > 55) &
# Only trade when the fast MA is above the slow MA
(dataframe['fastMA'] > dataframe['slowMA'])
# Or trade when the fase MA crosses above the slow MA (This is a choice...)
# (qtpylib.crossed_above(dataframe['fastMA'], dataframe['slowMA']))
)
),
'buy'] = 1
return dataframe
There are two indications that tell me that I should leave a position. These are:
- fastMA is below slowMA or
- the current candle close gets below the lowest low over the last 10 candles.
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
# Close or do not trade when fastMA is below slowMA
(dataframe['fastMA'] < dataframe['slowMA'])
# Or close position when the close price gets below the last lowest candle price configured
# (AKA candle based (Trailing) stoploss)
| (dataframe['close'] < dataframe['last_lowest'])
# | (dataframe['close'] < dataframe['fastMA'])
),
'sell'] = 1
return dataframe
Backtesting the strategy
I have done my backtesting on this strategy and aleady got some interesting results with the default settings on the different timeframes.
An overview of the initial backtest results shows that the 4 hour timeframe already shows a whopping 8917% profits.
========================================================== ENTER TAG STATS ===========================================================
| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|-------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------|
| TOTAL | 1780 | 3.00 | 5342.54 | 89173.471 | 8917.35 | 3 days, 14:41:00 | 715 0 1065 40.2 |
======================================================= EXIT REASON STATS ========================================================
| Exit Reason | Exits | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % |
|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
| exit_signal | 1408 | 344 0 1064 24.4 | -4.1 | -5769.6 | -205534 | -576.96 |
| trailing_stop_loss | 357 | 357 0 0 100 | 29.07 | 10376.6 | 277270 | 1037.66 |
| roi | 12 | 12 0 0 100 | 59.94 | 719.28 | 15997.2 | 71.93 |
| force_exit | 3 | 2 0 1 66.7 | 5.4 | 16.21 | 1439.63 | 1.62 |
======================================================== LEFT OPEN TRADES REPORT =========================================================
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|------------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------|
| SUSHI/USDT | 1 | 9.06 | 9.06 | 812.292 | 81.23 | 4 days, 0:00:00 | 1 0 0 100 |
| XMR/USDT | 1 | 9.04 | 9.04 | 793.508 | 79.35 | 1 day, 20:00:00 | 1 0 0 100 |
| ALGO/USDT | 1 | -1.89 | -1.89 | -166.165 | -16.62 | 1 day, 4:00:00 | 0 0 1 0 |
| TOTAL | 3 | 5.40 | 16.21 | 1439.635 | 143.96 | 2 days, 8:00:00 | 2 0 1 66.7 |
================== SUMMARY METRICS ==================
| Metric | Value |
|-----------------------------+---------------------|
| Backtesting from | 2017-08-17 04:00:00 |
| Backtesting to | 2022-01-01 08:00:00 |
| Max open trades | 10 |
| | |
| Total/Daily Avg Trades | 1780 / 1.11 |
| Starting balance | 1000 USDT |
| Final balance | 90173.471 USDT |
| Absolute profit | 89173.471 USDT |
| Total profit % | 8917.35% |
| CAGR % | 179.62% |
| Profit factor | 1.36 |
| Trades per day | 1.11 |
| Avg. daily profit % | 5.58% |
| Avg. stake amount | 2695.819 USDT |
| Total trade volume | 4798558.253 USDT |
| | |
| Best Pair | XRP/USDT 405.76% |
| Worst Pair | XTZ/USDT -54.87% |
| Best trade | XRP/USDT 59.94% |
| Worst trade | DOGE/USDT -70.12% |
| Best day | 10296.371 USDT |
| Worst day | -9700.259 USDT |
| Days win/draw/lose | 329 / 871 / 356 |
| Avg. Duration Winners | 4 days, 17:38:00 |
| Avg. Duration Loser | 2 days, 20:36:00 |
| Rejected Entry signals | 67060 |
| Entry/Exit Timeouts | 0 / 0 |
| | |
| Min balance | 986.921 USDT |
| Max balance | 106168.397 USDT |
| Max % of account underwater | 39.94% |
| Absolute Drawdown (Account) | 39.94% |
| Absolute Drawdown | 42401.098 USDT |
| Drawdown high | 105168.397 USDT |
| Drawdown low | 62767.299 USDT |
| Drawdown Start | 2021-05-12 00:00:00 |
| Drawdown End | 2021-07-25 16:00:00 |
| Market change | 1550.04% |
=====================================================
These profits are mainly caused by the trailing stop loss set. Which had 357 wins with an average profit of about 30%.
Another small portion of the profit was due to the ROI setting and the main cause of loss was the exit signal.
That last one was to be expected because the whole purpose of the exit when price closes below the lowest low of the last 10 candles to exit a trade quickly if markets turned out to get bearish.
So 60% of the trades were quick losses and 40% were trend riding opportunities.
Hyperparameter optimization
Since the trading bot can optimize ROI, stoploss AND these trailing stoploss settings by default, I can also check what the results could be with optimized parameters.
So I have optimized these parameters and did another set of backtests on the 4 hour timeframe which already gave the best results.
Hyperoparameter optimization results
With the optimized parameters this strategy backtest results are simply unbeleivable (and as said at the beginning of this post I actually really should not beleive these).
If I wanted I als could have programmed the other indicators to be optimized, but I did not want it to be too complex code and a curve fitted strategy.
The settings for the RSI are pretty common, although 7 is a maybe a pretty quick setting.
But the SMA settings of 21, 50 and 200 should be familiar to everybody that has some experience in trading.
The setting to calculate the slope and last lowest candle are educated but tested quesses. And I am happy with these settings.
But If you like this strategy and want to put some effort in it, i recon that you could change this code and also optimise all these other settings as well. But beware that you are not curve fitting too much as I said. And be sure to forward test this thouroghly.
Anyway after hyperopting I got these settings back and with these settings I did one more backtest on the 4 hour timeframe with these results:
========================================================= ENTER TAG STATS ==========================================================
| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|-------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
| TOTAL | 5306 | 1.13 | 5983.74 | 234221.440 | 23422.14 | 1 day, 2:06:00 | 3845 71 1390 72.5 |
======================================================= EXIT REASON STATS ========================================================
| Exit Reason | Exits | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % |
|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
| trailing_stop_loss | 3664 | 3664 0 0 100 | 4.46 | 16337.7 | 942129 | 1633.77 |
| exit_signal | 1361 | 5 0 1356 0.4 | -8.59 | -11690.8 | -744481 | -1169.08 |
| roi | 247 | 176 71 0 100 | 9.4 | 2322.7 | 138638 | 232.27 |
| stop_loss | 32 | 0 0 32 0 | -30.34 | -970.86 | -98578.7 | -97.09 |
| force_exit | 2 | 0 0 2 0 | -7.52 | -15.03 | -3485.73 | -1.5 |
======================================================== LEFT OPEN TRADES REPORT =========================================================
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|------------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------|
| ALGO/USDT | 1 | -4.95 | -4.95 | -1153.058 | -115.31 | 20:00:00 | 0 0 1 0 |
| SUSHI/USDT | 1 | -10.09 | -10.09 | -2332.668 | -233.27 | 1 day, 12:00:00 | 0 0 1 0 |
| TOTAL | 2 | -7.52 | -15.03 | -3485.726 | -348.57 | 1 day, 4:00:00 | 0 0 2 0 |
================== SUMMARY METRICS ==================
| Metric | Value |
|-----------------------------+---------------------|
| Backtesting from | 2017-08-17 04:00:00 |
| Backtesting to | 2022-01-01 08:00:00 |
| Max open trades | 10 |
| | |
| Total/Daily Avg Trades | 5306 / 3.32 |
| Starting balance | 1000 USDT |
| Final balance | 235221.44 USDT |
| Absolute profit | 234221.44 USDT |
| Total profit % | 23422.14% |
| CAGR % | 248.07% |
| Profit factor | 1.28 |
| Trades per day | 3.32 |
| Avg. daily profit % | 14.66% |
| Avg. stake amount | 5778.29 USDT |
| Total trade volume | 30659607.163 USDT |
| | |
| Best Pair | LINK/USDT 403.70% |
| Worst Pair | KSM/USDT -29.15% |
| Best trade | ETH/USDT 18.88% |
| Worst trade | BNB/USDT -30.34% |
| Best day | 19369.728 USDT |
| Worst day | -32595.359 USDT |
| Days win/draw/lose | 695 / 491 / 370 |
| Avg. Duration Winners | 15:56:00 |
| Avg. Duration Loser | 2 days, 1:35:00 |
| Rejected Entry signals | 60286 |
| Entry/Exit Timeouts | 0 / 0 |
| | |
| Min balance | 990.719 USDT |
| Max balance | 258710.423 USDT |
| Max % of account underwater | 38.35% |
| Absolute Drawdown (Account) | 38.35% |
| Absolute Drawdown | 81053.432 USDT |
| Drawdown high | 210355.328 USDT |
| Drawdown low | 129301.896 USDT |
| Drawdown Start | 2021-05-12 08:00:00 |
| Drawdown End | 2021-07-02 04:00:00 |
| Market change | 1550.04% |
=====================================================
Now I must say that my mouth fell open after I saw these results. I just simply could not believe them (and I was right – remember).
I thought that the original settings had proven their value but after optimizing the parameters it turned out to give spectacular gains.
However…
If you look at the coins that benefit the most of these new settings, then you will see only altoins that also had major pumps in 2021.
And if you look at the number one coin that had the most benefits of these new settings, namely LUNA, then you must realize that trading is indeed a risky business and you should take profits whenever you can. And not get married your crypto in any way.
Result for strategy slope_is_dope2
=========================================================== BACKTESTING REPORT ===========================================================
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|------------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------|
| LUNA/USDT | 84 | 1.67 | 140.62 | 19022.528 | 1902.25 | 15:57:00 | 69 0 15 82.1 |
| XTZ/USDT | 113 | 0.96 | 108.25 | 18815.082 | 1881.51 | 23:18:00 | 84 2 27 74.3 |
| WAVES/USDT | 102 | 2.73 | 278.91 | 15724.719 | 1572.47 | 1 day, 0:09:00 | 78 2 22 76.5 |
| XRP/USDT | 227 | 1.75 | 396.90 | 13764.097 | 1376.41 | 23:50:00 | 172 3 52 75.8 |
| BAT/USDT | 85 | 1.02 | 86.68 | 13520.375 | 1352.04 | 1 day, 1:47:00 | 58 1 26 68.2 |
| UMA/USDT | 25 | 1.65 | 41.15 | 13423.959 | 1342.40 | 15:31:00 | 20 0 5 80.0 |
| EGLD/USDT | 57 | 2.18 | 124.11 | 12163.240 | 1216.32 | 19:26:00 | 47 0 10 82.5 |
| NEAR/USDT | 39 | 1.38 | 53.99 | 10018.974 | 1001.90 | 14:34:00 | 31 0 8 79.5 |
| ICX/USDT | 91 | 0.66 | 60.26 | 9251.883 | 925.19 | 1 day, 1:48:00 | 64 2 25 70.3 |
| TRX/USDT | 153 | 1.50 | 228.92 | 9147.510 | 914.75 | 22:56:00 | 113 3 37 73.9 |
| ZEC/USDT | 67 | 1.23 | 82.31 | 8542.113 | 854.21 | 1 day, 1:40:00 | 48 0 19 71.6 |
| FIL/USDT | 27 | 2.96 | 80.03 | 8428.334 | 842.83 | 18:58:00 | 21 0 6 77.8 |
| LTC/USDT | 235 | 0.87 | 204.99 | 7711.907 | 771.19 | 1 day, 8:07:00 | 165 5 65 70.2 |
| BCH/USDT | 140 | 1.39 | 195.14 | 7190.630 | 719.06 | 1 day, 7:05:00 | 101 5 34 72.1 |
| ADA/USDT | 257 | 0.73 | 187.75 | 7178.346 | 717.83 | 1 day, 1:56:00 | 187 3 67 72.8 |
| BNB/USDT | 317 | 1.04 | 329.85 | 6907.497 | 690.75 | 1 day, 5:29:00 | 216 8 93 68.1 |
| COMP/USDT | 53 | 1.85 | 98.22 | 6451.001 | 645.10 | 18:20:00 | 43 0 10 81.1 |
| YFI/USDT | 27 | 0.90 | 24.29 | 6317.644 | 631.76 | 19:42:00 | 20 0 7 74.1 |
| ONT/USDT | 66 | 0.17 | 11.52 | 6163.574 | 616.36 | 1 day, 1:35:00 | 46 0 20 69.7 |
| ZIL/USDT | 100 | 1.38 | 138.27 | 5804.882 | 580.49 | 16:00:00 | 79 0 21 79.0 |
| GRT/USDT | 18 | 2.11 | 37.99 | 5619.720 | 561.97 | 12:13:00 | 14 0 4 77.8 |
| THETA/USDT | 193 | 1.88 | 361.89 | 4998.944 | 499.89 | 22:50:00 | 156 2 35 80.8 |
| ATOM/USDT | 131 | 0.58 | 76.42 | 4878.776 | 487.88 | 22:01:00 | 98 1 32 74.8 |
| NEO/USDT | 161 | 1.15 | 184.90 | 4622.372 | 462.24 | 1 day, 0:40:00 | 119 0 42 73.9 |
| UNI/USDT | 57 | 2.37 | 134.89 | 4603.452 | 460.35 | 16:13:00 | 50 0 7 87.7 |
| VET/USDT | 134 | 0.87 | 116.95 | 4494.221 | 449.42 | 1 day, 1:42:00 | 96 2 36 71.6 |
| MKR/USDT | 29 | 1.55 | 44.97 | 4414.744 | 441.47 | 20:41:00 | 23 0 6 79.3 |
| STX/USDT | 78 | 1.52 | 118.35 | 3723.097 | 372.31 | 21:45:00 | 59 1 18 75.6 |
| ETC/USDT | 70 | 0.07 | 4.64 | 3527.059 | 352.71 | 1 day, 4:58:00 | 44 1 25 62.9 |
| DOT/USDT | 94 | 1.08 | 101.73 | 3523.399 | 352.34 | 1 day, 4:13:00 | 66 1 27 70.2 |
| DASH/USDT | 61 | 1.67 | 101.93 | 2982.009 | 298.20 | 1 day, 1:38:00 | 47 0 14 77.0 |
| DGB/USDT | 16 | 0.53 | 8.47 | 2732.795 | 273.28 | 12:15:00 | 13 0 3 81.2 |
| XMR/USDT | 154 | 0.59 | 90.22 | 2707.864 | 270.79 | 1 day, 13:15:00 | 100 2 52 64.9 |
| ALGO/USDT | 56 | 0.55 | 30.53 | 2644.900 | 264.49 | 1 day, 4:13:00 | 37 0 19 66.1 |
| ZRX/USDT | 66 | 2.70 | 178.52 | 2536.305 | 253.63 | 21:27:00 | 50 0 16 75.8 |
| EOS/USDT | 151 | 0.58 | 87.88 | 2495.695 | 249.57 | 1 day, 6:09:00 | 102 4 45 67.5 |
| XEM/USDT | 40 | 0.06 | 2.40 | 1490.799 | 149.08 | 13:48:00 | 30 0 10 75.0 |
| ETH/USDT | 304 | 1.21 | 368.37 | 1325.315 | 132.53 | 1 day, 9:04:00 | 209 7 88 68.8 |
| AAVE/USDT | 50 | 1.08 | 53.98 | 678.147 | 67.81 | 16:34:00 | 39 0 11 78.0 |
| FTT/USDT | 50 | 0.03 | 1.27 | 457.893 | 45.79 | 1 day, 13:31:00 | 29 2 19 58.0 |
| DOGE/USDT | 42 | 0.56 | 23.56 | -329.217 | -32.92 | 21:54:00 | 29 1 12 69.0 |
| OMG/USDT | 66 | 1.65 | 108.97 | -992.198 | -99.22 | 17:13:00 | 51 1 14 77.3 |
| LINK/USDT | 270 | 1.50 | 403.70 | -1697.084 | -169.71 | 1 day, 1:39:00 | 206 1 63 76.3 |
| BTC/USDT | 265 | 0.78 | 207.72 | -1995.353 | -199.54 | 1 day, 17:33:00 | 166 8 91 62.6 |
| SNX/USDT | 63 | 0.29 | 18.17 | -2330.519 | -233.05 | 15:30:00 | 47 0 16 74.6 |
| DCR/USDT | 38 | 1.70 | 64.64 | -2354.054 | -235.41 | 19:47:00 | 29 0 9 76.3 |
| REN/USDT | 71 | 0.38 | 27.20 | -3709.288 | -370.93 | 21:01:00 | 53 0 18 74.6 |
| KSM/USDT | 48 | -0.61 | -29.15 | -3798.489 | -379.85 | 21:05:00 | 35 0 13 72.9 |
| SUSHI/USDT | 43 | -0.01 | -0.64 | -6606.597 | -660.66 | 14:08:00 | 31 0 12 72.1 |
| XLM/USDT | 222 | 0.82 | 181.09 | -11971.564 | -1197.16 | 1 day, 1:12:00 | 155 3 64 69.8 |
| TOTAL | 5306 | 1.13 | 5983.74 | 234221.440 | 23422.14 | 1 day, 2:06:00 | 3845 71 1390 72.5 |
========================================================= ENTER TAG STATS ==========================================================
| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|-------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
| TOTAL | 5306 | 1.13 | 5983.74 | 234221.440 | 23422.14 | 1 day, 2:06:00 | 3845 71 1390 72.5 |
======================================================= EXIT REASON STATS ========================================================
| Exit Reason | Exits | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % |
|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
| trailing_stop_loss | 3664 | 3664 0 0 100 | 4.46 | 16337.7 | 942129 | 1633.77 |
| exit_signal | 1361 | 5 0 1356 0.4 | -8.59 | -11690.8 | -744481 | -1169.08 |
| roi | 247 | 176 71 0 100 | 9.4 | 2322.7 | 138638 | 232.27 |
| stop_loss | 32 | 0 0 32 0 | -30.34 | -970.86 | -98578.7 | -97.09 |
| force_exit | 2 | 0 0 2 0 | -7.52 | -15.03 | -3485.73 | -1.5 |
The future is unknown
Now, to compare this even more with the original settings, Bitcoin had a nice profit with those original ones. With the new settings however, Bitcoin trading did not benefit at all from these adjusted settings and even proved to be a loser.
But this is all with the benefit of hindsight and you have to remember that these backtests are done with a dataset that ended in december 2021. So when you started to let your bot trade with this strategy at the beginning of 2022, then you would not know that all of this would happen.
This is the same with a dataset that I download today and backtest with that. I will not know what’s going to happen tomorrow, next week or next year. Maybe 2023 will be much worse and white swans will become rare…
So you have to take into account the risks that come with trading. Also with the help of a bot in this case.
Anyway, lets pretend 2022 did not happen and see at which position this strategy would enter the total strategy league with these findings…
Strategy league
And it looks like we have a new number 2 in the League of strategies. And again I did not expect to see this strategy entering this high when I started these backtests.
It certainly has its advantage to take profits quickly with a trailing stop loss if you think the market is turning against you. Locking in these gains. You can see that with the winrate of over 70 percent.
If it only had a lower drawdown, then it could possibly have the number one spot on this league.
But again, the indicators I use are fairly simple and straightforward in comparison with the NFIX. And the rules for entering and exiting a trade can be easily programmed into bot code, which takes the human factor out of trading. And then provide these results it’s pretty amazing.
I wonder if anybody can verify these results when they backtest this strategy on their own bot.
Final remarks
Again, the results of this backtests are clearly too good to be true and more research is needed to make clear why this happens and how this could be avoided with future backtests.
I will propably revisit this strategy later on and backtest it again to see what realistic results are. Then I will post these on my blog and adjust the strategy league with this.
A final thought is that this discovery can also be true with the NFIX strategy, which is currently on the first spot of the league. a 93% winrate is clearly another ‘too good to be true’ situation and it is unknown why these results come forward in backtesting. With that strategy however it is reasonable to assume that we will never really know why these results occur because of its complex (and much) code. Only forward testing will show its real potential.
But that is the same for each strategy that is discussed in this blog and my video’s. So always do your own research and make your own conclusion before doing any actual trading.
Good luck and goodbye!