YD_Divergence_RSI+CMF
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Yonsei_dent
//                                   
//  \\  //   ⇗⩸⇖   ||   ||  ⇗⁼⁼⁼⁼⁼   ∥⁼⁼⁼⁼  ⁼⁼₪⁼⁼         ₪₪⁼⁼⁼⁼⇘                            
//   \\//   ∥  ∥  ||\\ ||  ⇘‗‗‗‗‗   ∥‗‗‗‗    ‖           ||    ∥  ⇗⁼⁼⁼⇘  ∥⇗⁼⁼⁼⇘  ‗‗‖‗‗
//    ‖‖    ∥  ∥  || \\||        ⇘  ∥        ‖           ||    ∥  ‖⇘₌₌⇗  ∥    ∥   ‖
//    ‖‖     ⇘⩸⇙   ||   ||   ‗‗‗‗‗⇗  ∥‗‗‗‗  ‗‗‖‗‗   ‗‗‗   ||‗‗‗‗⇗   ⇘‗‗‗   ∥    ∥   ‖‗‗⇗  ©©
//
//@version=5
indicator("YD_Divergence_RSI+CMF", overlay = true, format = format.price)

// 변수설정-1. Pivot
pivotgroup      = 'Pivot Setting'
pivottip        = 'If pivot length is too long, The signal will be delayed. The range for "Pivot Length" is set from 1 to 50.'
price_length    = input.int(5, "Pivot Length", minval = 1, maxval = 50, group = pivotgroup, tooltip = pivottip)
pivotprice      = input.string('High/Low (고/저가)', "Pivot Reference", options = ['High/Low (고/저가)','Close (종가)'], group = pivotgroup)
pivotplot       = input.bool(false, 'Pivot High/Low Marker', group = pivotgroup)

// 변수설정-2. RSI
rsigroup        = 'RSI Setting'
rsi_length      = input.int(14, 'RSI Length', minval =1, maxval = 50, group = rsigroup)
rsi             = ta.rsi(close, rsi_length)

// 변수설정-3. Chaikin Money Flow
cmfgroup        = 'CMF Setting'
cmf_length      = input.int(20, 'CMF Length', minval=1, maxval = 50, group = cmfgroup)
mfv             = close==high and close==low or high==low ? 0 : ((2*close-low-high)/(high-low))*volume
cmf             = math.sum(mfv, cmf_length) / math.sum(volume, cmf_length)
var cumVol      = 0.
cumVol         += nz(volume)
if barstate.islast and cumVol == 0
    runtime.error("No volume is provided by the data vendor.")

// 변수설정-4. label
labelgroup       = 'Label Setting'
bullbearlabel    = input.string('Bullish/Bearish', 'Bull/Bear Label Text', options = ['Bullish/Bearish', 'Bull/Bear','None'], group = labelgroup)
divergencelabel  = input.string('Divergence', 'Divergence Label Text', options = ['Divergence','None'], group = labelgroup)
bullshow      = input.bool(true, '', inline = 'bull', group = labelgroup)
bulllinecol   = input.color(color.green, 'Bullish Divergence Line   ', inline = 'bull', group = labelgroup)
bulllinewid   = input.int(1, '', maxval = 4, minval = 1, inline = 'bull', group = labelgroup)
bulllinest    = input.string('────', '', options=['────', 'ㅡㅡㅡㅡ', '••••••••'], inline = 'bull', group = labelgroup)
bearshow      = input.bool(true, '', inline = 'bear', group = labelgroup)
bearlinecol   = input.color(color.red, 'Bearish Divergence Line  ', inline = 'bear', group = labelgroup)
bearlinewid   = input.int(1, '', maxval = 4, minval = 1, inline = 'bear', group = labelgroup)
bearlinest    = input.string('────', '', options=['────', 'ㅡㅡㅡㅡ', '••••••••'], inline = 'bear', group = labelgroup)
bulllabelshow = input.bool(true, '', inline = 'bulllabel', group = labelgroup)
bulllabelcol  = input.color(color.green, 'Bullish Divergence Label   ', inline = 'bulllabel', group = labelgroup)
bulllabeltext = input.string('Normal', '', options = ['Tiny', 'Small', 'Normal', 'Large', 'Auto'], inline = 'bulllabel', group= labelgroup)
bulllabelst   = input.string('Label', '', options = ['Arrow', 'Label', 'Triangle', 'Text'], inline = 'bulllabel', group = labelgroup)
bearlabelshow = input.bool(true, '', inline = 'bearlabel', group = labelgroup)
bearlabelcol  = input.color(color.red, 'Bearish Divergence Label  ', inline = 'bearlabel', group = labelgroup)
bearlabeltext = input.string('Normal', '', options = ['Tiny', 'Small', 'Normal', 'Large', 'Auto'], inline = 'bearlabel', group= labelgroup)
bearlabelst   = input.string('Label', '', options = ['Arrow', 'Label', 'Triangle', 'Text'], inline = 'bearlabel', group = labelgroup)
lastshow      = input.bool(false, '  Display Only the Last Label.', group = labelgroup)
labeltextcol  = input.color(color.white, 'Label Text Color', group = labelgroup)


// divergence 생성조건
// 1-1. 가격의 Pivot High / Low 구하기
php            = ta.pivothigh(pivotprice=='High/Low (고/저가)'?high:close, price_length, price_length)
plp            = ta.pivotlow(pivotprice=='High/Low (고/저가)'?low:close, price_length, price_length)
phfound        = na(php) ? false : true
plfound        = na(plp) ? false : true
plot(pivotplot?php:na, "Pivot High", color = color.green, linewidth = 3, style = plot.style_linebr, offset = -(price_length))
plot(pivotplot?plp:na, "Pivot Low", color = color.red, linewidth = 3, style = plot.style_linebr, offset = -(price_length))

// 2. 가격의 HH, LL 갱신
is_price_higher = ta.valuewhen(phfound, pivotprice=='High/Low (고/저가)'?high[price_length]:close[price_length], 0) > ta.valuewhen(phfound, pivotprice=='High/Low (고/저가)'?high[price_length]:close[price_length], 1)
is_price_lower  = ta.valuewhen(plfound, pivotprice=='High/Low (고/저가)'?low[price_length]:close[price_length], 0) < ta.valuewhen(plfound, pivotprice=='High/Low (고/저가)'?low[price_length]:close[price_length], 1)

// 3. 지표의 divergence
is_rsi_lower   = ta.valuewhen(phfound, rsi[price_length], 0) < ta.valuewhen(phfound, rsi[price_length], 1)
is_rsi_higher  = ta.valuewhen(plfound, rsi[price_length], 0) > ta.valuewhen(plfound, rsi[price_length], 1)
is_cmf_lower   = ta.valuewhen(phfound, cmf[price_length], 0) < ta.valuewhen(phfound, cmf[price_length], 1)
is_cmf_higher  = ta.valuewhen(plfound, cmf[price_length], 0) > ta.valuewhen(plfound, cmf[price_length], 1)

// 4. 2개의 피봇간 Range 제한
_inRange(cond) =>
    bars = ta.barssince(cond == true)
    5 <= bars and bars <= 50

// Bullish RSI Divergence 조건설정
bull_rsi_div = plfound and is_price_lower and is_rsi_higher and _inRange(plfound[1]) 

// Bullish CMF Divergence 조건설정
bull_cmf_div = plfound and is_price_lower and is_cmf_higher and _inRange(plfound[1]) 

// Bearish RSI Divergence 조건설정
bear_rsi_div = phfound and is_price_higher and is_rsi_lower and _inRange(phfound[1]) 

// Bearish CMF Divergence 조건설정
bear_cmf_div = phfound and is_price_higher and is_cmf_lower and _inRange(phfound[1]) 

// 함수 설정
RSIdirection() =>
    if bull_rsi_div and bullbearlabel == 'Bullish/Bearish'
        "Bullish RSI"
    else if bull_rsi_div and bullbearlabel == 'Bull/Bear'
        "Bull RSI"
    else if bear_rsi_div and bullbearlabel == 'Bullish/Bearish'
        "Bearish RSI"
    else if bear_rsi_div and bullbearlabel == 'Bull/Bear'
        "Bear RSI"
    else if bull_rsi_div or bear_rsi_div and bullbearlabel == 'None'
        "RSI"
    else
        na 

CMFdirection() =>
    if bull_cmf_div and bullbearlabel == 'Bullish/Bearish'
        "Bullish CMF"
    else if bull_cmf_div and bullbearlabel == 'Bull/Bear'
        "Bull CMF"
    else if bear_cmf_div and bullbearlabel == 'Bullish/Bearish'
        "Bearish CMF"
    else if bear_cmf_div and bullbearlabel == 'Bull/Bear'
        "Bear CMF"
    else if bull_cmf_div or bear_cmf_div and bullbearlabel == 'None'
        "CMF"
    else
        na 

divergence() =>
    if divergencelabel == 'Divergence'
        " Divergence"
    else if divergencelabel == 'None'
        na

bullbear() =>
    if bull_rsi_div or bull_cmf_div
        "Bull"
    else if bear_rsi_div or bear_cmf_div
        "Bear"
    else
        na

switchLineStyle(x) =>
    switch x
        '────'        => line.style_solid
        'ㅡㅡㅡㅡ'    => line.style_dashed
        '••••••••'        => line.style_dotted

switchsize(x) =>
    switch x
        'Tiny'   => size.tiny
        'Small'  => size.small
        'Normal' => size.normal
        'Large'  => size.large
        'Auto'   => size.auto

switchbulllabel(x) =>
    switch x
        'Arrow'   => label.style_arrowup
        'Label'  => label.style_label_up
        'Triangle' => label.style_triangleup
        'Text'  => label.style_text_outline

switchbearlabel(x) =>
    switch x
        'Arrow'   => label.style_arrowdown
        'Label'  => label.style_label_down
        'Triangle' => label.style_triangledown
        'Text'  => label.style_text_outline

drawdl(x1, y1, x2, y2, col, wid, st) =>
    dl = line.new(x1, y1, x2, y2, color = col, width = wid, style = switchLineStyle(st))

bullbearRSI   = RSIdirection()
bullbearCMF   = CMFdirection()
divergence    = divergence()
rsiresult     = ""
CMFresult     = ""

// 입력값 호출
if not na(bullbearRSI)
    rsiresult := bullbearRSI + divergence
else
    rsiresult := ""

if not na(bullbearCMF)
    CMFresult := bullbearCMF + divergence
else
    CMFresult := ""

var finalresult = "na"
if na(bullbearRSI) and not na(bullbearCMF)
    finalresult := CMFresult
else if not na(bullbearRSI) and na(bullbearCMF)
    finalresult := rsiresult
else if not na(bullbearRSI) and not na(bullbearCMF)
    finalresult := rsiresult + "\n" + CMFresult

// Divergence Line 작도
var line[] buline = array.new_line(0)
var line[] beline = array.new_line(0)
var line bullline = na
var line bearline = na
var int dhx1 = na, var float dhy1 = na
var int dhx2 = na, var float dhy2 = na
var int dlx1 = na, var float dly1 = na
var int dlx2 = na, var float dly2 = na

if plfound
    dhx1 := dhx2, dhy1 := dhy2
    dhx2 := bar_index[price_length], dhy2 := plp
    if bullbear() == "Bull" and bullshow
        bullline := drawdl(dhx1, dhy1, dhx2, dhy2, bulllinecol, bulllinewid, bulllinest)
        array.push(buline, bullline)
        array.reverse(buline)
        if lastshow and array.size(buline) >= 2
            line.delete(array.pop(buline))

if phfound
    dlx1 := dlx2, dly1 := dly2
    dlx2 := bar_index[price_length], dly2 := php
    if bullbear() == "Bear" and bearshow
        bearline := drawdl(dlx1, dly1, dlx2, dly2, bearlinecol, bearlinewid, bearlinest)
        array.push(beline, bearline)
        array.reverse(beline)
        if lastshow and array.size(beline) >= 2
            line.delete(array.pop(beline))

// Divergence Mark 작도
var label[] bulabel = array.new_label(0)
var label[] belabel = array.new_label(0)

if bullbear() == "Bull" and bulllabelshow
    bulllabel = label.new(
         x = bar_index[price_length],
         y = low[price_length],
         style = switchbulllabel(bulllabelst),
         text = finalresult,
         color = bulllabelcol,
         size = switchsize(bulllabeltext),
         yloc = yloc.belowbar,
         textcolor = labeltextcol
         )
    array.push(bulabel, bulllabel)
    array.reverse(bulabel)
    if lastshow and array.size(bulabel) >= 2
        label.delete(array.pop(bulabel))

if bullbear() == "Bear" and bearlabelshow
    bearlabel = label.new(
         x = bar_index[price_length],
         y = high[price_length],
         style = switchbearlabel(bearlabelst),
         text = finalresult,
         color = bearlabelcol,
         size = switchsize(bearlabeltext),
         yloc = yloc.abovebar,
         textcolor = labeltextcol
         )
    array.push(belabel, bearlabel)
    array.reverse(belabel)
    if lastshow and array.size(belabel) >= 2
        label.delete(array.pop(belabel))

// Alert 설정
if bull_rsi_div
    alert("RSI Bullish Divergence", alert.freq_once_per_bar_close)
else if bear_rsi_div
    alert("RSI Bearish Divergence", alert.freq_once_per_bar_close)
else if bull_cmf_div
    alert("CMF Bullish Divergence", alert.freq_once_per_bar_close)
else if bear_cmf_div
    alert("CMF Bearish Divergence", alert.freq_once_per_bar_close)