Home Creators Posts Import Register Favorites Logout

Content

Introduction

Hi there everybody and welcome to another video/post in which I will test another trading algorithm I found on the Internet. This time it is an algorithm called BBRSITV. At first hand I assumed it would make use of the Elliot wave oscillator, volume weighted moving average and modified Elder ray index because they were so promiment in the code. But later on I found out that is going to use only the Elliot Wave Oscillator and a Bollinger band overlay on the RSI.

Hence the name BBRSI. So I am very interested to find out how this algo will perform under my backtesting circumstances.

And to give you an appertiser, it does perform well. So watch this video until the end to find out how it will perform and if it has the potential to make us some profits in the future.

The strategy

Just as with many files I currently have in my repository I found this one a while ago when I was hoarding the internet for strategies that I wanted to investigate and test. Back then I was never interested in logging where I got this strategy from because I was never thinking of making videos and blogposts about these.

Searching on Google I found these two sources that also mention this strategy and maybe one of these sources is the original one. So if you recognize this algo and it’s yours, then leave a comment in the comment section so we can give credits where credits are due.

So back to the strategy.

The author has configured three custom indicators here. Called EWO, vwma and moderi. And searching on the internet these stand for Elliot Wave Oscillator, Volume Weighted Moving Average and Modified Elder Ray Index.

# Elliot Wave Oscillator: https://help.tc2000.com/m/69445/l/755860-elliott-wave-oscillator
def EWO(dataframe, ema_length=5, ema2_length=35):
df = dataframe.copy()
ema1 = ta.EMA(df, timeperiod=ema_length)
ema2 = ta.EMA(df, timeperiod=ema2_length)
emadif = (ema1 - ema2) / df['close'] * 100
return emadif
# Volume Weighted Moving Average
def vwma(dataframe: DataFrame, length: int = 10):
"""Indicator: Volume Weighted Moving Average (VWMA)"""
# Calculate Result
pv = dataframe['close'] * dataframe['volume']
vwma = Series(ta.SMA(pv, timeperiod=length) / ta.SMA(dataframe['volume'], timeperiod=length))
return vwma
# Modified Elder Ray Index
def moderi(dataframe: DataFrame, len_slow_ma: int = 32) -> Series:
slow_ma = Series(ta.EMA(vwma(dataframe, length=len_slow_ma), timeperiod=len_slow_ma))
return slow_ma >= slow_ma.shift(1)  # we just need true & false for ERI trend

Now at first I was pretty exited because this would then give me some insights in the signalling reliability of these indicators. But you will find out later it is not the case, so that’s somewhat of a bummer. But don’t let me discourage you beforehand. Things will get better.

The strategy can be optimized on the buy and sell signals. And also ofcourse on the ROI and Stop loss settings.

# Buy hyperspace params:
buy_params = {
"ewo_high": 4.86,
"for_ma_length": 22,
"for_sigma": 1.74,
}
# Sell hyperspace params:
sell_params = {
"for_ma_length_sell": 65,
"for_sigma_sell": 1.895,
"rsi_high": 72,
}
# ROI table:  # value loaded from strategy
minimal_roi = {
"0": 0.1
}
# Stoploss:
stoploss = -0.25  # value loaded from strategy

The author also has incorporated two protections in this strategy, namely the LowProfitPairs and the MaxDrawdown protections. Where the LowProfitPairs is a built-in protection method that aims to identify and stop trading on pairs that have consistently low profitability. And the MaxDrawdown is a built-in protection method that monitors the maximum drawdown of a strategy. This method will stop trading if the strategy’s drawdown exceeds 20% (0.2) over a lookback period of 24 candles.

{
"method": "LowProfitPairs",
"lookback_period_candles": 60,
"trade_limit": 1,
"stop_duration": 60,
"required_profit": -0.05
},
{
"method": "MaxDrawdown",
"lookback_period_candles": 24,
"trade_limit": 1,
"stop_duration_candles": 12,
"max_allowed_drawdown": 0.2
},

Then comes a section where more of the optimization settings are determined for the buy and sell spaces.

ewo_high = DecimalParameter(0, 7.0, default=buy_params['ewo_high'], space='buy', optimize=True)
for_sigma = DecimalParameter(0, 10.0, default=buy_params['for_sigma'], space='buy', optimize=True)
for_sigma_sell = DecimalParameter(0, 10.0, default=sell_params['for_sigma_sell'], space='sell', optimize=True)
rsi_high = IntParameter(60, 100, default=sell_params['rsi_high'], space='sell', optimize=True)
for_ma_length = IntParameter(5, 80, default=buy_params['for_ma_length'], space='buy', optimize=True)
for_ma_length_sell = IntParameter(5, 80, default=sell_params['for_ma_length_sell'], space='sell', optimize=True)

And the proposed timeframe and some other protections:

# Optimal timeframe for the strategy
timeframe = '5m'
# Protection
fast_ewo = 50
slow_ewo = 200

Then the actual indicators are determined in the populate indicator method below. In the original file there are a lot of lines commented out, which will then not be used. The lines below are those that are used by the backtest engine:

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
src = 'close'
for_rsi = 14
for_mult = 2
for_sigma = 0.1
dataframe['rsi'] = ta.RSI(dataframe[src], for_rsi)
dataframe['rsi_4'] = ta.RSI(dataframe[src], 4)
if self.config['runmode'].value == 'hyperopt':
for for_ma in range(5, 81):
dataframe[f'basis_{for_ma}'] = ta.EMA(dataframe['rsi'], for_ma)
dataframe[f'dev_{for_ma}'] = ta.STDDEV(dataframe['rsi'], for_ma)
else:
dataframe[f'basis_{self.for_ma_length.value}'] = ta.EMA(dataframe['rsi'], self.for_ma_length.value)
dataframe[f'basis_{self.for_ma_length_sell.value}'] = ta.EMA(dataframe['rsi'], self.for_ma_length_sell.value)
dataframe[f'dev_{self.for_ma_length.value}'] = ta.STDDEV(dataframe['rsi'], self.for_ma_length.value)
dataframe[f'dev_{self.for_ma_length_sell.value}'] = ta.STDDEV(dataframe['rsi'], self.for_ma_length_sell.value)
h1 = 70
h2 = 30
dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo)
return dataframe

And finally we come to the actual algorithm that decides when to buy and when to sell. From the code that is provided I understand that the buy signal is given when:

The RSI is below the lower bollinger band that is created of an EMA of the RSI. That lower bollinger band also is multiplied by a for_sigma value.

Also the Elliot wave oscillator should be higher than a configured high level value.

And the volume should be above 0

def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['rsi'] < (dataframe[f'basis_{self.for_ma_length.value}'] - (dataframe[f'dev_{self.for_ma_length.value}'] * self.for_sigma.value))) &
(dataframe['EWO'] >  self.ewo_high.value) &
(dataframe['volume'] > 0)
),
'buy'] = 1
return dataframe
And the algorithmic sell signal will be triggered if the following conditions are met. Besides the ROI and stoploss triggers ofcourse:
The RSI is higher then a configured rsi_high level or if the RSI is higher than the upper RSI bollinger band that is also multiplied by a sell sigma value.
Also the volume should be above 0.
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(
(dataframe['rsi'] > self.rsi_high.value) |
(dataframe['rsi'] > dataframe[f'basis_{self.for_ma_length_sell.value}'] + ((dataframe[f'dev_{self.for_ma_length_sell.value}'] * self.for_sigma_sell.value)))
) &
(dataframe['volume'] > 0)
),
'sell'] = 1
return dataframe

So as far as I can understand from the code, that is also pretty hard to read because of all the commented out lines by the way, the RSI has a bollinger band as an overlay and the algorithm buys when the RSI is oversold and sells when the RSI is overbought.

But please add your comments to the comments section if I get this totally wrong ofcourse.

Other strategy classes

A little bit furter down in the code, there arfe other strategy classes defined by the author. These classes all inherits the properties and methods from the main class.

In total there are 6 classes (inc. the original class) and each class has slightly, and sometimes not so slightly differences in comparison with the original buy and sell settings. Like for example different ROI and Stop loss settings, Sigma settings and other specific parameters.

For this video it is a little bit too much to go over each and every class, determining its performance and optimizing its parameters. That might be a challenge for you to find out.

I will only test the main strategy class here for this video / post to see if further investigation is advisable.

Initial backtest result

The initial backtest result of this spot trading strategy looks very promising. The best timeframe is 15 minutes and it has over 3400 percent profits in the past. The winrate is 60 percent and on average you have 4 winning trades and only 2 losing trades. With a maximum winstreak of 23 trades in the backtest. The maximum drawdown was only 33 percent.
Also all the ratios all are above 3. Which indicates that this strategy has a high potential to also perform good in the future. You probably also won’t go wrong with your preferred pairs with this algo since 72 percent of my configured pairs have positive results here.

Initial backtest results

Also the profit plot looks good in my opinion. The only pair that has a strong negative reaction to this algorithm is MRK.

It also seems that the backtest engine does not trade that often on the 15 minute timeframe, hence the almost 3400 trades over the complete backtesting period. It is possible that RSI oversold and overbought circumstances, as initially configured in the code do not occur that often.

Furthermore, the most noticable thing for me here are the three relative drawdown trenches that all seem to reach around 30% drawdown.

Initial profit plot

So all in al a pretty well performing trading algorithm right from the start. Let me now optimize the buy and sell settings to see if this can optimized more for an even better performance.

And ofcourse beware that we are entering overfitting territory here.

Optimization and results

It happens so and then that optimizing the parameters have positive influence on one performance indicator of an algorithm. But it also can go at a cost and other factors get worse performances.

That is what’s happening here in this case as well. The parameter optimization improved the sortino and sharpe ratio’s. Just as is asked to the system. But unfortunately the overall performance of the algorithm get’s worse. Profits dwindle, there are less pairs that respond well to this strategy and the drawdown explodes to 45 percent maximum.

Also the profit chart does not look that great after optimization. The drawdown is larger and deeper and overall profits lower. The bot has traded more over the dataset but somehow has less profits and these more trades also cause to have more losing trades as well.

So I must conclude that optimization in this case is not beneficial for the strategy and the author has done a good job on the original code’s settings.

The other classes performance

While I wrote the outline of this post/video I also did some backtests of the other configured classes in this code. I showed you these earlier. I used the best 15 minute timeframe for these tests and got the following results back:

The BBRSI4 class even showed higher results in this backtest. The settings of this class are below:

class BBRSITV4(BBRSITV):
minimal_roi = {
"0": 0.07
}
ignore_roi_if_buy_signal = True
startup_candle_count = 400
stoploss = -0.3  # value loaded from strategy
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['rsi'] < (dataframe[f'basis_{self.for_ma_length.value}'] - (dataframe[f'dev_{self.for_ma_length.value}'] * self.for_sigma.value)))
&
(
(
(dataframe['EWO'] > self.ewo_high.value)
&
(dataframe['EWO'] < 10)
)
|
(
(dataframe['EWO'] >= 10)
&
(dataframe['rsi'] < 40)
)
)
&
(dataframe['rsi_4'] < 25)
&
(dataframe['volume'] > 0)
# &
# (dataframe["roc_bbwidth_max"] < 70)
),
'buy'] = 1
return dataframe

It could be that the strategy could score better with these settings, but I followed the code authors preference of the original class for my test. Nonetheless it’s worth mentioning in this video though so that you can choose for yourself which version to use in your situation.

Conclusion and strategy league

So at the end of this post/video we can conclude that this RSI bollinger strategy seems to have great potential here . The original or main algorithm enters the league on the second spot. Which moves the popular Clucmay strategy to the third spot. In some cases the BBRSI strategy does not score as good as the Clucmay and it’s higher score is mainly caused by the higher profit percentage that has been measured. But don’t get me wrong here. I think that seriously investigating if any of these 5 to 10 best found strategies fit your specific trading situation has possibly great potential for succesfull future trades.

You can also try to combine the best of all these strategies to create an even better potential trading algorithm. But remember to rigorously test this with back and forward testing before using any of these in real market conditions with actual money.

Files

The files of this strategy were already posted earlier on my Patreon page and are located here: https://www.patreon.com/posts/86047174

Comments

No comments found for this post.