For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

# Bullish and Bearish Divergence MACD/RSI

• Hello,

I'm trying to figure out how can I access these signals?

To get it i thought for example to find first low, than the previous low indexes.
Then get prices compare them. Then get indicator's values and compare them too. I got stuck at getting second low/high. Please help.

``````self.high_first = btind.FindFirstIndexHighest(self.data.high, period=self.p.hl_period)
self.high_second = btind.FindFirstIndexHighest(self.data.high(self.high_first-1), period=self.p.hl_period)
self.low_first = btind.FindFirstIndexLowest(self.data.low, period=self.p.hl_period)
self.low_second = btind.FindFirstIndexLowest(self.data.low(self.low_first-1), period=self.p.hl_period)``````

• I might don't know something and I'm reinventing the wheel, It would be great if somebody point me the right direction.

• ``````self.high_first = btind.FindFirstIndexHighest(self.data.high, period=self.p.hl_period)
self.high_second = btind.FindFirstIndexHighest(self.data.high(self.high_first-1), period=self.p.hl_period)
``````

The problem is that `self.data.high(self.high_first - 1)` is not a valid construct. Because `self.high_first` will be determined at runtime, whereas a delayed line (using parenthesis) needs to know the value from how many periods ago it will returning.

A potential coding

``````class SecondHigh(bt.ind.PeriodN):
lines = ('first_high', 'second_high',)

def __init__(self):
self.hf = self.lines.first_high  = bt.ind.FindFirstIndexHighest(self.data.high, period=self.p.period)

def next(self):
# 0 is valid return value for now, make sure to get at least 1 item
iterable = self.data.get(size=self.hf + 1)
m = max(iterable)
self.lines.second_high = next(i for i, v in enumerate(reversed(iterable)) if v == m)
``````

Finding the index of the maximum is not made with the better `iterable.index(max(iterable))` to comply with the idea in backtrader that the current index is `0`.

The `FindFirstXXX` family of functions return the indices in absolute value and this is also done here .

Note: this is a handcrafted snippet which may have typos and not work at all.

• ``````self.high_first = btind.FindFirstIndexHighest(self.data.high, period=self.p.hl_period)
self.high_second = btind.FindFirstIndexHighest(self.data.high(self.high_first-1), period=self.p.hl_period)
``````

The problem is that `self.data.high(self.high_first - 1)` is not a valid construct. Because `self.high_first` will be determined at runtime, whereas a delayed line (using parenthesis) needs to know the value from how many periods ago it will returning.

A potential coding

``````class SecondHigh(bt.ind.PeriodN):
lines = ('first_high', 'second_high',)

def __init__(self):
self.hf = self.lines.first_high  = bt.ind.FindFirstIndexHighest(self.data.high, period=self.p.period)

def next(self):
# 0 is valid return value for now, make sure to get at least 1 item
iterable = self.data.get(size=self.hf + 1)
m = max(iterable)
self.lines.second_high = next(i for i, v in enumerate(reversed(iterable)) if v == m)
``````

Finding the index of the maximum is not made with the better `iterable.index(max(iterable))` to comply with the idea in backtrader that the current index is `0`.

The `FindFirstXXX` family of functions return the indices in absolute value and this is also done here .

Note: this is a handcrafted snippet which may have typos and not work at all.

Thanks I will try your example

• @backtrader I created an indicator that works, but sometimes I face error like this:
ValueError: max() arg is an empty sequence

Here is the code:

``````class RSIDivergence(bt.ind.PeriodN):
lines = ('signal',)
params = dict(
rsi_period=14,
hl_period=100,
hl_min=20
)

# plotinfo = dict(
#     subplot=True,
#     plotlinelabels=True, plotlinevalues=True, plotvaluetags=True,
# )

# plotlines = dict(
#     high_first_price=dict(_name='high_first_price', color='red', ls='-'),
#     high_second_price=dict(_name='high_second_price', color='blue', ls='-'),
#     low_first_price=dict(_name='low_first_price', color='red', ls='-'),
#     low_second_price=dict(_name='low_second_price', color='blue', ls='-'),
# )

def __init__(self):
self.hfi = bt.ind.FindFirstIndexHighest(self.data.high, period=self.p.hl_period)
self.lfi = bt.ind.FindFirstIndexLowest(self.data.low, period=self.p.hl_period)
self.rsi = bt.ind.RSI_Safe(period=self.p.rsi_period)

def signal_get(self):
signal = 0
if self.hfp >= self.hsp:
if self.rsi[-int(self.hfi)] < self.rsi[-int(self.hsi)]:
print('bearish', self.rsi[-int(self.hfi)], self.rsi[-int(self.hsi)])
signal -= 1

if self.lfp <= self.lsp:
if self.rsi[-int(self.lfi)] > self.rsi[-int(self.lsi)]:
print('bullish', self.rsi[-int(self.hfi)], self.rsi[-int(self.hsi)])
signal += 1

return signal

def next(self):
iterable = self.data.high.get(size=int(self.hfi) + self.p.hl_min)
m = max(iterable)
self.hsi = next(i for i, v in enumerate(reversed(iterable)) if v == m) + self.p.hl_min

iterable = self.data.low.get(size=int(self.lfi) + self.p.hl_min)
m = min(iterable)
self.lsi = next(i for i, v in enumerate(reversed(iterable)) if v == m) + self.p.hl_min

self.hfp = self.data.high[-int(self.hfi)]
self.hsp = self.data.high[-int(self.hsi)]
self.lfp = self.data.low[-int(self.lfi)]
self.lsp = self.data.low[-int(self.lsi)]

# self.lines.high_first_price = self.hfp
# self.lines.high_second_price = self.hsp
# self.lines.low_first_price = self.lfp
# self.lines.low_second_price = self.lsp
self.lines.signal = self.signal_get()``````

• iterable

I have created the fix, hope you can include similar indicator for RSI/MACD in the main branch:

``````class RSIDivergence(bt.ind.PeriodN):
lines = ('signal',)
params = dict(
rsi_period=30,
hl_period=100,
hl_min=25
)

def __init__(self):
self.hfi = bt.ind.FindFirstIndexHighest(self.data.high, period=self.p.hl_period)
self.lfi = bt.ind.FindFirstIndexLowest(self.data.low, period=self.p.hl_period)
self.rsi = bt.ind.RSI_Safe(period=self.p.rsi_period)

def signal_get(self):
signal = 0
if self.hfp >= self.hsp:
if self.rsi[-int(self.hfi)] < self.rsi[-int(self.hsi)]:
signal -= 1

if self.lfp <= self.lsp:
if self.rsi[-int(self.lfi)] > self.rsi[-int(self.lsi)]:
signal += 1

return signal

def next(self):
h_iterable = self.data.get(size=self.p.hl_period, ago=-int(self.hfi) - self.p.hl_min)
l_iterable = self.data.get(size=self.p.hl_period, ago=-int(self.lfi) - self.p.hl_min)

if len(h_iterable) > 0 and len(l_iterable) > 0:
m = max(h_iterable)
self.hsi = next(i for i, v in enumerate(reversed(h_iterable)) if v == m) + int(self.hfi) + self.p.hl_min

m = min(l_iterable)
self.lsi = next(i for i, v in enumerate(reversed(l_iterable)) if v == m) + int(self.lfi) + self.p.hl_min

self.hfp = self.data.high[-int(self.hfi)]
self.hsp = self.data.high[-int(self.hsi)]
self.lfp = self.data.low[-int(self.lfi)]
self.lsp = self.data.low[-int(self.lsi)]

self.lines.signal = self.signal_get()
else:
self.lines.signal = 0``````

• Thank you.

• Hello,

I'm trying use your custom indicator RSIDivergence but I don't understand how I can use it?
Do you have a simple example ?
I am sorry for my english and I am not good developper

• I don't understand why nobody answer me ?

• class RSIDivergence(bt.ind.PeriodN):
lines = ('signal',)

I am not the author but looking at these excerpts from the code

``````class RSIDivergence(bt.ind.PeriodN):
lines = ('signal',)
...
...
def signal_get(self):
signal = 0
if self.hfp >= self.hsp:
if self.rsi[-int(self.hfi)] < self.rsi[-int(self.hsi)]:
signal -= 1

if self.lfp <= self.lsp:
if self.rsi[-int(self.lfi)] > self.rsi[-int(self.lsi)]:
signal += 1

return signal

def next(self):
...
...

self.lines.signal = self.signal_get()
else:
self.lines.signal = 0
``````

The indicator has:

• A line named `signal` which is the output indicating the divergence
• It can have the values `-1`, `0` or `1` which should be self-explanatory

• @backtrader thanks you very much . I'm happy now ! I will test soon :D

-1 for Bearish Divergence
1 for Bullish Divergence ????

• @vasu-dev
yes I think:
-1 for Bearish Divergence
1 for Bullish Divergence
but I have result not good... and you?

Someone have an example working good ?

• After testing the code above and plotting the divergences that it found, I think that the issue is with this line:

``````self.hfi = bt.ind.FindFirstIndexHighest(self.data.high, period=self.p.hl_period)
``````

It looks for the highest point (same for the lowest) within the hl_period (100 bars)

Then in the following line it looks again backwards from that point to find the second high

``````h_iterable = self.data.get(size=self.p.hl_period, ago=-int(self.hfi) - self.p.hl_min)
``````

So basically the code returns signals for very old divergences. If you are on daily chart, you will try to trade on a divergence that is 100 days old.

So the first day after the high point it signals a sell, then for the next 100 days it still signals a sell !

I have amended the first line to look for a high/low point for the last day only.
In this way if the divergence is growing then it's fine you still get a sell signal, but if the divergence is gone then you don't try to keep selling for 100 days.

});
{"ft_lang_label":"__label__en","ft_lang_prob":0.57116055,"math_prob":0.92308587,"size":9617,"snap":"2019-43-2019-47","text_gpt3_token_len":2663,"char_repetition_ratio":0.18526995,"word_repetition_ratio":0.44178364,"special_character_ratio":0.2701466,"punctuation_ratio":0.22447993,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9951261,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2019-11-15T00:13:47Z\",\"WARC-Record-ID\":\"<urn:uuid:5729bb29-d256-46a3-bff5-601e74d20ee7>\",\"Content-Length\":\"111355\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:2f29407e-ddaf-4439-9276-7b175b47c943>\",\"WARC-Concurrent-To\":\"<urn:uuid:a41f1ed3-1a58-4bd2-b63a-0cc7a01145da>\",\"WARC-IP-Address\":\"37.120.190.102\",\"WARC-Target-URI\":\"https://community.backtrader.com/topic/1216/bullish-and-bearish-divergence-macd-rsi/14\",\"WARC-Payload-Digest\":\"sha1:ZY7X6GJ5HYEJQ3X3NL2FGDLLZAILG7HQ\",\"WARC-Block-Digest\":\"sha1:TNOID3DBG3F642UQ6OZUZS4MGELAIH3M\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2019/CC-MAIN-2019-47/CC-MAIN-2019-47_segments_1573496668544.32_warc_CC-MAIN-20191114232502-20191115020502-00219.warc.gz\"}"}