Sortino improves on Sharpe by only penalizing downside volatility. Better for asymmetric returns—upside volatility doesn't hurt the score.
Sortino = (Rp - Rtarget) / DownsideDeviation
// Calculate Sortino Ratio
function sortinoRatio(returnPct, targetPct, downsideDev) {
const excessReturn = returnPct - targetPct;
return excessReturn / downsideDev;
}
// Downside deviation (only negative returns count)
function downsideDeviation(returns, target) {
const negativeReturns = returns.filter(r => r < target);
if (negativeReturns.length === 0) return 0;
const squaredDeviations = negativeReturns.map(r => (r - target) ** 2);
const avgSquaredDev = squaredDeviations.reduce((a,b)=>a+b,0) / returns.length;
return Math.sqrt(avgSquaredDev);
}