Constantly Applied Pressure Index (CAP index)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Mynicknameislion

//@version=5
indicator("Constantly Applied Pressure Index (CAP index)", "CAP index")
lookback = input.int(title="Lookback Period", defval = 8)
inverse = input.bool(title="Inverse indicator", defval=true)
smoothingType = input.string(title="Line Smoothing Mehtod",  defval="WMA", options=[ "EMA", "SMA", "RMA", "WMA", "None"])
smoothingPeriod = input.int(title="Line Smoothing Period", defval = 17)
src = input(title="Source", defval=close)
predictions = input.bool(title="Determine trend of indicator", defval=true)
baseLine = input.bool(title="Show Baseline", defval = true)
noFail = input.bool(title="No failing trend indication", defval=false)
strengthCurve = input.float(title="Strength Curve One", defval=0.005)
strengthCurveTwo = input.float(title="Strength Curve Two", defval=0.001)


var temp = 0.0
upsideScore = 100.0
downsideScore = 100.0
baseSide = if src > src[1]
    "bull"
else
    "bear"


//Step 1
if baseSide == "bull"
    upsideScore *= 1.05
    downsideScore *- 1.025
else
    upsideScore *- 1.025
    downsideScore *= 1.05


//Step 2


qtyOfHigherCloses(lookback, src) =>
	int result = 0
	for i = 1 to lookback
		if src[i] > src
			result += 1
	result
	
qtyOfLowerCloses(lookback, src) =>
	int result = 0
	for i = 1 to lookback
		if src[i] < src
			result += 1
	result

bullLookback = qtyOfHigherCloses(lookback, src)
bearLookback = qtyOfLowerCloses(lookback, src)

side = if baseSide == "bull"
    bullLookback
else
    bearLookback

temp := 0
for i = 1 to math.min(side, 5)
    temp += strengthCurve * (1 / i)

if baseSide == "bull"
    upsideScore *= (temp + 1)
else
    downsideScore *= (temp + 1)

side := baseSide == "bull" ? bearLookback : bullLookback

temp := 0
for i = 1 to math.min(side, 8)
    temp += strengthCurveTwo * (i * i)

if baseSide == "bull"
    downsideScore *= (temp + 1)
else
    upsideScore *= (temp + 1)


//Step 3

bearchange = 0.0
bullchange = 0.0
temp := 0

for i = 1 to lookback
    if src[i] > src[i - 1]
        temp += 1
        bullchange += src[i] - src[i - 1]
    else
        bearchange += src[i - 1] - src[i]

bullchange /= temp
bearchange /= (lookback - temp)
temp := 0

if bullchange > bearchange
    temp := (downsideScore / 100) * 5
    downsideScore -= temp
    upsideScore += temp
else
    temp := (upsideScore / 100) * 5
    downsideScore += temp
    upsideScore -= temp


//Step 4
bullVolume = 0.0
bearVolume = 0.0
temp := 0

for i = 1 to lookback
    if src[i] > src[i - 1]
        temp += 1
        bullVolume += volume[i]
    else
        bearVolume += volume[i]

bullVolume /= temp
bearVolume /= (lookback - temp)

if bullVolume > bearVolume and baseSide == "bull"
    temp := (downsideScore / 100) * 3
    downsideScore -= temp
    upsideScore += temp
else if bullVolume > bearVolume and baseSide == "bear"
    temp := (downsideScore / 100) * 5
    downsideScore -= temp
    upsideScore += temp
else if bullVolume < bearVolume and baseSide == "bear"
    temp := (upsideScore / 100) * 3
    downsideScore += temp
    upsideScore -= temp
else if bullVolume < bearVolume and baseSide == "bull"
    temp := (upsideScore / 100) * 5
    downsideScore += temp
    upsideScore -= temp


//Plotting and trend calculation    
overall = upsideScore - downsideScore

smoothed = 0.0

if smoothingType == "EMA"
    smoothed := ta.ema(overall, smoothingPeriod)
else if smoothingType == "SMA"
    smoothed := ta.sma(overall, smoothingPeriod)
else if smoothingType == "RMA"
    smoothed := ta.rma(overall, smoothingPeriod)
else if smoothingType == "WMA"
    smoothed := ta.wma(overall, smoothingPeriod)
else
    smoothed := overall

if inverse
    smoothed *= -1

var trend = 0 // 1 is strong up, 2 weak up and 0 is failing, negatives are down
var trendHigh = 0.0
var failed = false

if ta.crossover(smoothed, 0)
    trend := 1
    trendHigh := -1
    failed := false
else if ta.crossover(0, smoothed)
    trend := -1
    trendHigh := 1
    failed := false

if trend == 1
    if smoothed <= smoothed[1] and smoothed[1] <= smoothed[2]
        trend := 2

if trend == -1
    if smoothed >= smoothed[1] and smoothed[1] >= smoothed[2]
        trend := -2
        

if trend == 2 and not noFail
    if smoothed > trendHigh
        trendHigh := smoothed
    if smoothed < (trendHigh - (trendHigh * 0.1))
        trend := 0

if trend == -2 and not noFail
    if smoothed < trendHigh
        trendHigh := smoothed
    if smoothed > (trendHigh + (trendHigh * 0.1))
        trend := 0

if trend == 0
    if not failed and smoothed > 0
        if smoothed > (trendHigh - (trendHigh * 0.05))
            trend := 2
            failed := true
    if not failed and smoothed < 0
        if smoothed < (trendHigh + (trendHigh * 0.05))
            trend := -2
            failed := true

plot(0, "Baseline", display = (baseLine ? display.all : display.none), color=color.gray)
plot(smoothed, "", predictions ? na : color.white)
plot(smoothed, "Failing Trend Line", predictions ? (trend == 0 ? color.gray : na ) : na)
plot(smoothed, "Strong Trend Line", predictions ? (trend == 1 ? color.lime : (trend == -1 ? color.red : na)) : na)
plot(smoothed, "Weaktrend Line", predictions ? (trend == 2 ? color.olive : (trend == -2 ? color.maroon : na)) : na)