Sortino Ratio
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © JoeCA9772

//@version=5
indicator(title="Sortino Ratio", overlay=false)

// determine annualization factor (not all timeframes are currently supported)
days = input(365, title="Trading Days In A Year")

multiplier = if (timeframe.period == "60") // hourly
    days * 24
else if (timeframe.period == "D") // daily
    days
else if (timeframe.period == "W") // weekly
    days / 52
else if (timeframe.period == "M") // monthly
    days / 12

// number of bars to include in the calculation
window = input(1460, title="Lookback Window")

// zero, risk-free rate, etc. (example: for Fed average inflation target of 2%, use 2 and not 0.02)
r = input(0, title="Minimum Acceptable Return Percentage") / 100

// 1-period log-return
ret = math.log(close / close[1])

// piecewise squared difference considering only negative log-returns
sq_diff = if ret < 0
    math.pow(ret - r, 2)
else
    0

// annualized expected return
mean_ret = ta.sma(ret, window) * multiplier

// annualized downside deviation
dn_dev = math.sqrt(ta.sma(sq_diff, window) * multiplier)

// Sortino Ratio
sortino = (mean_ret - r) / dn_dev

// background
fill(hline(0, linestyle=hline.style_solid, color=color.rgb(255,255,255,90)), hline(1, linestyle=hline.style_dashed), color=color.rgb(255,0,0,95))

plot(sortino, color=color.rgb(255,0,0,50))
