Home Creators Posts Import Register Favorites Logout
haven't archived this post yet. have a subscription? use the importer!

Downloads

  • Slope-is-dope-files.7z
  • spot_config.json

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!

Comments

Dutch Algotrading

Ok, some formatting is not great, like tables and special fonts (to mark coding) are not allowed so it seems that I have to come up with a solution for this. However headings and images seem to work well as it stands now.

mr_vii

Hi, using freqtrade backtesting --timeframe 4h --timeframe-detail 15m --config config_spot.json --export none --cache none --strategy slope_is_dope2 i've got Tot Profit %: 10.55 Backtesting with data from 2022-12-04 00:00:00 up to 2023-08-21 12:00:00 (260 days) Why this diff?

Dutch Algotrading

I cannot say from this side. I do not use the timeframe detail. Maybe that's the difference here. I also assume that the data/config you use is exactly the same as mine here also. Otherwise it could be that pair data, which is missing, is not included in the test.