Rolling Sortino Ratio (SORTINO)
Summary
The rolling Sortino ratio: the mean return in excess of a minimum acceptable return (MAR), divided by the downside deviation, over a trailing window, scaled to a year. It is the Sharpe ratio with upside volatility taken out of the denominator: only returns below the MAR count as risk. Above 0 the window's returns beat the MAR on average; the larger the value, the more return per unit of downside.
Chart
Chart metadata i
Drawn on the price pane over the close as a line; below it, a separate indicator pane with a zero line showing outReal as a solid line.
Metadata flags used: outReal: line, positive, negative
Reference data (CSV) · Chart (SVG)
Formula
With simple returns , per-bar minimum acceptable return , excess returns and annualization , over the trailing returns:
The result is when no return in the window is below the MAR, and NaN when every return equals it.
Notes
- The downside deviation divides by the full window
n: a return above the MAR counts innand adds zero to the sum. This is the definition of Sortino and Price (1994) and the divisor of Bacon's worked example; dividing byn−1, or by the number of returns below the MAR, gives a different value. - The mean is arithmetic, not compounded.
- A window with no return below the MAR has no downside: the result is +Inf, and NaN when every return equals the MAR. In a rising market this is common. With an annualization of 0 it is NaN there and 0 elsewhere.
- The MAR is per bar, in the same unit as the returns. For an annual rate
R, pass(1+R)^(1/A) − 1, whereAis the annualization; it is not de-annualized for you. - An annualization of 1 gives the raw per-bar ratio.
- A zero price leaves no return to measure from it: the return of the bar after it counts as 0.
Inputs
inReal— The price series; its returns are computed internally
Outputs
outReal— Annualized Sortino ratio of the trailing window, or +Inf or NaN where the window has no return below the MAR
Parameters
| Parameter | Type | Default | Accepted values | Description |
|---|---|---|---|---|
optInTimePeriod | integer | 20 | 2–100000 | Number of returns in the window; one price more is read |
optInMAR | real | 0 | any real | Minimum acceptable return per bar; returns below it are the downside |
optInAnnualization | real | 252 | ≥ 0 | Bars per year; the per-bar ratio is multiplied by its square root |
Properties
Numerical Stability: Start-Independent
| ☐ Overlap Input |
| ✅ Independent Y-Axis i |
| ☐ Candlestick |
| ✅ Can Output NaN or ±Inf i |
| ☐ Identity at Period 1 |
| ☐ Display Shift |
| ☐ Uses Transcendental |
| ☐ Input Must Be Positive |
Example
#include <stdio.h>
#include <ta_libc.h>
int n = 252;
double series[252]; /* your data, oldest first */
double out[252];
int outBegIdx, outNBElement;
TA_Initialize();
TA_SORTINO( 0, n - 1, series, 20, 0.0, 252.0, &outBegIdx, &outNBElement, out );
printf( "%d values from bar %d; last out = %f\n", outNBElement, outBegIdx, out[outNBElement - 1] );use ta_lib::Core;
let series = vec![0.0; 252]; // your data, oldest first
let mut out = vec![0.0; 252];
let core = Core::new();
let range = core.sortino(0, series.len() - 1, &series, 20, 0.0, 252.0, &mut out)?;
println!("{} values from bar {}; last out = {}", range.count, range.beg_idx, out[range.count - 1]);import io.github.talib.Core;
import io.github.talib.OutRange;
double[] series = new double[252]; // your data, oldest first
double[] out = new double[252];
Core core = Core.DEFAULT;
OutRange r = core.sortino(0, series.length - 1, series, 20, 0.0, 252.0, out);
System.out.println(r.count() + " values from bar " + r.begIdx() + "; last out = " + out[r.count() - 1]);using System;
using TALib;
var series = new double[252]; // your data, oldest first
var outReal = new double[252];
var core = Core.Default;
OutRange r = core.Sortino(0, series.Length - 1, series, 20, 0.0, 252.0, outReal);
Console.WriteLine($"{r.Count} values from bar {r.BegIdx}; last outReal = {outReal[r.Count - 1]}");import { sortino } from 'ta-lib';
const series = new Float64Array(252); // your data, oldest first
const { begIdx, values } = sortino(series, {
timePeriod: 20,
mar: 0,
annualization: 252,
});
console.log(values.length + ' values from bar ' + begIdx + '; last values = ' + values[values.length - 1]);Implementation
Added in 0.8.4.
TA-Lib Definition: sortino.c · sortino.yaml
| Native | File |
|---|---|
| C | ta_SORTINO.c |
| Rust | sortino.rs |
| Java | Core_SORTINO.java |
| C# | Core_SORTINO.cs |
| TypeScript | sortino.ts |
Python: talib.SORTINO, see ta-lib-python.
TA-Lib is also available for R and more using a wrapper.
Aliases
Sortino Ratio, Rolling Sortino, Downside Risk-Adjusted Return
See Also
References
- Sortino, F. A. and Price, L. N. "Performance Measurement in a Downside Risk Framework." The Journal of Investing, 3(3), Fall 1994, 59-64.
- Bacon, C. R. Practical Portfolio Performance Measurement and Attribution, 2nd ed. Wiley, 2008.