API Documentation

Portfolio analytics

Modules

OnlinePortfolioAnalytics.OnlinePortfolioAnalyticsModule

OnlinePortfolioAnalytics provides streaming portfolio analytics using online algorithms that process data incrementally without storing the full history.

Features

Usage

All types implement the OnlineStatsBase interface:

using OnlinePortfolioAnalytics

# Create a statistic
stat = Sharpe{Float64}()

# Feed observations one at a time
for return_value in returns
    fit!(stat, return_value)
end

# Get current value
result = value(stat)

For metrics requiring paired asset/benchmark data, use AssetBenchmarkReturn:

stat = Beta{Float64}()
fit!(stat, AssetBenchmarkReturn(0.05, 0.03))  # Asset +5%, Market +3%
value(stat)

MIT License

Copyright (c) 2024 FemtoTrader <femto.trader@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

source

Functions

OnlineStats.fit! Base.empty!

Asset return

OnlinePortfolioAnalytics.SimpleAssetReturnType
mutable struct SimpleAssetReturn{T} <: OnlinePortfolioAnalytics.AssetReturn{T}
SimpleAssetReturn{T}(; period::Int = 1)

Calculate simple (arithmetic) returns from a stream of price observations.

Simple returns measure the percentage change in price between two periods using the formula (Pt - P{t-k}) / P_{t-k}, where k is the period.

Mathematical Definition

$R_t = \frac{P_t - P_{t-k}}{P_{t-k}}$

Where:

  • $P_t$ = price at time t
  • $P_{t-k}$ = price k periods ago
  • $k$ = period (default: 1)

Parameters

  • period: Number of periods for return calculation (default: 1)

Edge Cases

  • Returns missing until period + 1 observations have been received
  • Returns missing if price at t-k is zero (division by zero avoided)

Fields

  • value::Union{Missing,T}: Current return value
  • n::Int: Number of observations
  • period::Int: Return calculation period

Example

stat = SimpleAssetReturn{Float64}()
fit!(stat, 100.0)  # First price observation
fit!(stat, 110.0)  # Second price observation
value(stat)        # Returns 0.1 (10% return)

See also: LogAssetReturn, CumulativeReturn

source
OnlinePortfolioAnalytics.LogAssetReturnType
mutable struct LogAssetReturn{T} <: OnlinePortfolioAnalytics.AssetReturn{T}
LogAssetReturn{T}(; period::Int = 1)

Calculate logarithmic (continuously compounded) returns from a stream of price observations.

Log returns are additive across time periods and are commonly used in financial modeling because they have better statistical properties than simple returns.

Mathematical Definition

$R_t = \ln\left(\frac{P_t}{P_{t-k}}\right)$

Where:

  • $P_t$ = price at time t
  • $P_{t-k}$ = price k periods ago
  • $k$ = period (default: 1)
  • $\ln$ = natural logarithm

Parameters

  • period: Number of periods for return calculation (default: 1)

Edge Cases

  • Returns missing until period + 1 observations have been received
  • Undefined behavior if price at t-k is zero or negative

Fields

  • value::Union{Missing,T}: Current return value
  • n::Int: Number of observations
  • period::Int: Return calculation period

Example

stat = LogAssetReturn{Float64}()
fit!(stat, 100.0)  # First price observation
fit!(stat, 110.0)  # Second price observation
value(stat)        # Returns ~0.0953 (log return)

See also: SimpleAssetReturn, CumulativeReturn

source

Mean return

OnlinePortfolioAnalytics.ArithmeticMeanReturnType
mutable struct ArithmeticMeanReturn{T} <: OnlinePortfolioAnalytics.AbstractMeanReturn{T}
ArithmeticMeanReturn{T}()

Calculate the arithmetic mean of returns from a stream of observations.

The arithmetic mean is the simple average of all returns. It is commonly used for short-term performance analysis but can overestimate long-term growth.

Mathematical Definition

$\bar{R} = \frac{1}{n}\sum_{i=1}^{n} R_i$

Where:

  • $R_i$ = return for period i
  • $n$ = number of observations

Edge Cases

  • Returns 0.0 when no observations (n=0)

Fields

  • value::T: Current mean return
  • n::Int: Number of observations
  • sum::Sum: Internal sum tracker

Example

stat = ArithmeticMeanReturn{Float64}()
fit!(stat, 0.05)   # 5% return
fit!(stat, -0.02)  # -2% return
fit!(stat, 0.03)   # 3% return
value(stat)        # Returns 0.02 (2% average)

See also: GeometricMeanReturn, StdDev

source
OnlinePortfolioAnalytics.GeometricMeanReturnType
mutable struct GeometricMeanReturn{T} <: OnlinePortfolioAnalytics.AbstractMeanReturn{T}
GeometricMeanReturn{T}()

Calculate the geometric mean of returns from a stream of observations.

The geometric mean accounts for compounding and provides a better measure of long-term average return than arithmetic mean. It represents the constant return rate that would produce the same final value.

Mathematical Definition

$G = \left(\prod_{i=1}^{n}(1+R_i)\right)^{1/n} - 1$

Where:

  • $R_i$ = return for period i
  • $n$ = number of observations

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns -1.0 if cumulative product becomes zero

Fields

  • value::T: Current geometric mean return
  • n::Int: Number of observations
  • prod::Prod: Internal product tracker

Example

stat = GeometricMeanReturn{Float64}()
fit!(stat, 0.10)   # 10% return
fit!(stat, -0.05)  # -5% return
fit!(stat, 0.08)   # 8% return
value(stat)        # Geometric mean return

See also: ArithmeticMeanReturn, CumulativeReturn

source

Cumulative return

OnlinePortfolioAnalytics.CumulativeReturnType
mutable struct CumulativeReturn{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
CumulativeReturn{T}()

Calculate the cumulative (total) return from a stream of periodic returns.

Cumulative return represents the total growth factor of an investment over the entire observation period using geometric compounding.

Mathematical Definition

$C = \prod_{i=1}^{n}(1+R_i)$

Where:

  • $R_i$ = return for period i
  • $n$ = number of observations

Note: The value represents the growth factor, not the percentage return. Subtract 1 to get the percentage cumulative return.

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns the running product as observations are added

Fields

  • value::T: Current cumulative growth factor
  • n::Int: Number of observations
  • prod::Prod: Internal product tracker

Example

stat = CumulativeReturn{Float64}()
fit!(stat, 0.10)   # 10% return
fit!(stat, -0.05)  # -5% return
fit!(stat, 0.03)   # 3% return
value(stat)        # Cumulative growth factor (e.g., 1.0785)
# Percentage return: value(stat) - 1 = 0.0785 (7.85%)

See also: AnnualizedReturn, DrawDowns, GeometricMeanReturn

source

Standard deviation

OnlinePortfolioAnalytics.StdDevType
mutable struct StdDev{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
StdDev{T}()

Calculate the sample standard deviation of returns from a stream of observations.

Standard deviation measures the volatility or dispersion of returns around the mean. It is a fundamental risk measure in portfolio analysis.

Mathematical Definition

$\sigma = \sqrt{\frac{1}{n-1}\sum_{i=1}^{n}(R_i - \bar{R})^2}$

Where:

  • $R_i$ = return for period i
  • $\bar{R}$ = mean return
  • $n$ = number of observations

Edge Cases

  • Returns 1.0 when no observations (initial value)
  • Returns 0.0 when only one observation (no variance)

Fields

  • value::T: Current standard deviation
  • n::Int: Number of observations
  • variance::Variance: Internal variance tracker

Example

stat = StdDev{Float64}()
fit!(stat, 0.05)   # 5% return
fit!(stat, -0.02)  # -2% return
fit!(stat, 0.03)   # 3% return
value(stat)        # Standard deviation of returns

See also: ArithmeticMeanReturn, Sharpe

source

Drawdowns

OnlinePortfolioAnalytics.DrawDownsType
mutable struct DrawDowns{T} <: OnlinePortfolioAnalytics.AbstractDrawDowns{T}
DrawDowns{T}()

Calculate the current drawdown from a stream of returns using the geometric method.

Drawdown measures the percentage decline from the peak cumulative return to the current cumulative return. This implementation uses geometric compounding where cumulative returns are computed as the product of (1 + return).

Mathematical Definition

For a sequence of returns r₁, r₂, ..., rₙ:

  • Cumulative return at time t: $C_t = \prod_{i=1}^{t}(1+R_i)$
  • Running peak at time t: $P_t = \max(C_1, C_2, ..., C_t)$
  • Drawdown at time t: $D_t = \frac{C_t}{P_t} - 1$

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns 0.0 at new peaks (no drawdown)
  • Returns negative values during drawdown periods

Fields

  • value::T: Current drawdown value (negative or zero)
  • n::Int: Number of observations
  • prod::Prod: Internal cumulative return tracker
  • extrema::Extrema: Internal peak tracker

Example

stat = DrawDowns{Float64}()
fit!(stat, 0.10)   # 10% gain - new peak
fit!(stat, -0.05)  # 5% loss - in drawdown
fit!(stat, -0.03)  # 3% loss - deeper drawdown
value(stat)        # Current drawdown (negative value)

See also: ArithmeticDrawDowns, MaxDrawDown

source
OnlinePortfolioAnalytics.ArithmeticDrawDownsType
mutable struct ArithmeticDrawDowns{T} <: OnlinePortfolioAnalytics.AbstractDrawDowns{T}
ArithmeticDrawDowns{T}()

Calculate the current drawdown from a stream of returns using the arithmetic method.

Drawdown measures the percentage decline from the peak cumulative return to the current cumulative return. This implementation uses arithmetic compounding where cumulative returns are computed as the sum of returns.

Mathematical Definition

For a sequence of returns r₁, r₂, ..., rₙ:

  • Cumulative return at time t: $C_t = 1 + \sum_{i=1}^{t} R_i$
  • Running peak at time t: $P_t = \max(C_1, C_2, ..., C_t)$
  • Drawdown at time t: $D_t = \frac{C_t}{P_t} - 1$

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns 0.0 at new peaks (no drawdown)
  • Returns negative values during drawdown periods

Fields

  • value::T: Current drawdown value (negative or zero)
  • n::Int: Number of observations
  • sum::Sum: Internal cumulative return tracker
  • extrema::Extrema: Internal peak tracker

Example

stat = ArithmeticDrawDowns{Float64}()
fit!(stat, 0.10)   # 10% gain - new peak
fit!(stat, -0.05)  # 5% loss - in drawdown
fit!(stat, -0.03)  # 3% loss - deeper drawdown
value(stat)        # Current drawdown (negative value)

See also: DrawDowns, MaxArithmeticDrawDown

source

Maximum Drawdown

OnlinePortfolioAnalytics.MaxDrawDownType
mutable struct MaxDrawDown{T} <: OnlinePortfolioAnalytics.AbstractMaxDrawDown{T}
MaxDrawDown{T}()

Track the maximum (worst) peak-to-trough decline using geometric return compounding.

Maximum drawdown is the largest percentage decline from a cumulative return peak to a subsequent trough. This implementation uses the geometric method where cumulative returns are computed as the product of (1 + return).

The value returns the most negative drawdown observed, following industry convention where "maximum drawdown" refers to the largest decline magnitude.

Mathematical Definition

For a sequence of returns r₁, r₂, ..., rₙ:

  • Cumulative return at time t: Cₜ = ∏ᵢ₌₁ᵗ (1 + rᵢ)
  • Running peak at time t: Pₜ = max(C₁, C₂, ..., Cₜ)
  • Drawdown at time t: Dₜ = Cₜ / Pₜ - 1
  • Maximum drawdown: min(D₁, D₂, ..., Dₙ)

Example

stat = MaxDrawDown{Float64}()
fit!(stat, 0.10)   # 10% gain
fit!(stat, -0.05)  # 5% loss
fit!(stat, -0.15)  # 15% loss
value(stat)        # Returns most negative drawdown observed (e.g., -0.19)

References

  • empyrical (Python): max_drawdown() returns negative value
  • PerformanceAnalytics (R): maxDrawdown() returns positive magnitude

See also: MaxArithmeticDrawDown, DrawDowns

source
OnlinePortfolioAnalytics.MaxArithmeticDrawDownType
mutable struct MaxArithmeticDrawDown{T} <: OnlinePortfolioAnalytics.AbstractMaxDrawDown{T}
MaxArithmeticDrawDown{T}()

Track the maximum (worst) peak-to-trough decline using arithmetic return compounding.

This implementation uses the arithmetic method where cumulative returns are computed as the sum of returns, suitable for simple (non-compounding) returns.

The value returns the most negative drawdown observed, following industry convention where "maximum drawdown" refers to the largest decline magnitude.

Mathematical Definition

For a sequence of returns r₁, r₂, ..., rₙ:

  • Cumulative return at time t: Cₜ = 1 + Σᵢ₌₁ᵗ rᵢ
  • Running peak at time t: Pₜ = max(C₁, C₂, ..., Cₜ)
  • Drawdown at time t: Dₜ = Cₜ / Pₜ - 1
  • Maximum drawdown: min(D₁, D₂, ..., Dₙ)

Example

stat = MaxArithmeticDrawDown{Float64}()
fit!(stat, 0.10)   # 10% gain
fit!(stat, -0.05)  # 5% loss
value(stat)        # Returns most negative drawdown observed

See also: MaxDrawDown, ArithmeticDrawDowns

source

Statistical moments

OnlinePortfolioAnalytics.AssetReturnMomentsType
mutable struct AssetReturnMoments{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsMultiOutput{T}
AssetReturnMoments{T}()

Calculate the first four statistical moments of returns from a stream of observations.

This type computes mean, standard deviation, skewness, and kurtosis simultaneously, providing a complete statistical profile of the return distribution. The output is a NamedTuple with fields :mean, :std, :skewness, and :kurtosis.

Mathematical Definition

  • Mean: $\bar{R} = \frac{1}{n}\sum_{i=1}^{n} R_i$
  • Standard deviation: $\sigma = \sqrt{\frac{1}{n-1}\sum_{i=1}^{n}(R_i - \bar{R})^2}$
  • Skewness: $\gamma_1 = \frac{\frac{1}{n}\sum_{i=1}^{n}(R_i - \bar{R})^3}{\sigma^3}$
  • Kurtosis: $\gamma_2 = \frac{\frac{1}{n}\sum_{i=1}^{n}(R_i - \bar{R})^4}{\sigma^4} - 3$ (excess kurtosis)

Edge Cases

  • Returns (mean=0.0, std=0.0, skewness=0.0, kurtosis=0.0) when no observations
  • Skewness and kurtosis require at least 3-4 observations for meaningful values

Fields

  • value::NamedTuple: Current moments as (mean, std, skewness, kurtosis)
  • n::Int: Number of observations
  • moments::Moments: Internal moments tracker

Example

stat = AssetReturnMoments{Float64}()
fit!(stat, 0.05)
fit!(stat, -0.02)
fit!(stat, 0.03)
fit!(stat, -0.01)
m = value(stat)
m.mean      # Mean return
m.std       # Standard deviation
m.skewness  # Skewness
m.kurtosis  # Excess kurtosis

See also: ArithmeticMeanReturn, StdDev

source

Sharpe ratio

OnlinePortfolioAnalytics.SharpeType
mutable struct Sharpe{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
Sharpe{T}(; period=252, risk_free=0)

Calculate the Sharpe ratio from a stream of periodic returns.

The Sharpe ratio measures risk-adjusted performance by dividing excess return (above risk-free rate) by volatility. Higher values indicate better risk-adjusted returns.

Mathematical Definition

$S = \sqrt{T} \times \frac{E[R] - r_f}{\sigma}$

Where:

  • $E[R]$ = expected (mean) return
  • $r_f$ = risk-free rate
  • $\sigma$ = standard deviation of returns
  • $T$ = annualization period

Parameters

  • period: Annualization factor (default: 252)
    • Daily: 252 (trading days per year)
    • Weekly: 52
    • Monthly: 12
    • Hourly: 252 × 6.5
  • risk_free: Risk-free rate per period (default: 0)

Edge Cases

  • Returns NaN when standard deviation is zero (all returns identical)
  • Returns 0.0 when no observations

Fields

  • value::T: Current Sharpe ratio
  • n::Int: Number of observations
  • mean::Mean: Internal mean tracker
  • stddev::StdDev: Internal standard deviation tracker
  • period::Int: Annualization factor
  • risk_free::T: Risk-free rate

Example

stat = Sharpe{Float64}(period=252, risk_free=0.0)
fit!(stat, 0.02)   # 2% return
fit!(stat, -0.01)  # -1% return
fit!(stat, 0.03)   # 3% return
value(stat)        # Annualized Sharpe ratio

See also: Sortino, Treynor, Omega

source

Sortino ratio

OnlinePortfolioAnalytics.SortinoType
mutable struct Sortino{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
Sortino{T}(; period=252, risk_free=0)

Calculate the Sortino ratio from a stream of periodic returns.

The Sortino ratio is similar to the Sharpe ratio but uses only downside deviation (volatility of negative returns) in the denominator, making it more appropriate for asymmetric return distributions.

Mathematical Definition

$So = \sqrt{T} \times \frac{E[R] - r_f}{\sigma_{down}}$

Where:

  • $E[R]$ = expected (mean) return
  • $r_f$ = risk-free rate
  • $\sigma_{down}$ = standard deviation of negative returns only
  • $T$ = annualization period

Parameters

  • period: Annualization factor (default: 252)
    • Daily: 252 (trading days per year)
    • Weekly: 52
    • Monthly: 12
    • Hourly: 252 × 6.5
  • risk_free: Risk-free rate per period (default: 0)

Edge Cases

  • Returns NaN or Inf when downside deviation is zero (no negative returns)
  • Returns 0.0 when no observations

Fields

  • value::T: Current Sortino ratio
  • n::Int: Number of observations
  • mean_ret::Mean: Internal mean return tracker
  • stddev_neg_ret::StdDev: Internal downside deviation tracker
  • period::Int: Annualization factor
  • risk_free::T: Risk-free rate

Example

stat = Sortino{Float64}(period=252, risk_free=0.0)
fit!(stat, 0.02)   # 2% return (positive, not included in downside)
fit!(stat, -0.01)  # -1% return (negative, included in downside)
fit!(stat, 0.03)   # 3% return
value(stat)        # Annualized Sortino ratio

See also: Sharpe, DownsideDeviation, Calmar

source

Annualized return

OnlinePortfolioAnalytics.AnnualizedReturnType
mutable struct AnnualizedReturn{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
AnnualizedReturn{T}(; period=252)

Calculate annualized return (CAGR - Compound Annual Growth Rate) from a stream of periodic returns using geometric compounding.

Mathematical Definition

For a sequence of returns r₁, r₂, ..., rₙ:

  • Cumulative return: C = ∏ᵢ₌₁ⁿ (1 + rᵢ)
  • Annualized return: (C)^(period/n) - 1

This is equivalent to the CAGR (Compound Annual Growth Rate) formula.

Parameters

  • period: Annualization factor (default 252 for daily returns)
    • Daily: 252 (trading days per year)
    • Weekly: 52
    • Monthly: 12
    • Hourly: 252 × 6.5

Fields

  • value::T: Current annualized return
  • n::Int: Number of observations
  • prod::Prod{T}: Internal product tracker for cumulative return
  • period::Int: Annualization factor

Example

stat = AnnualizedReturn()
fit!(stat, 0.01)   # 1% daily return
fit!(stat, 0.02)   # 2% daily return
fit!(stat, -0.01)  # -1% daily return
value(stat)        # Annualized return

See also: Calmar, CumulativeReturn

source

Calmar ratio

OnlinePortfolioAnalytics.CalmarType
mutable struct Calmar{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
Calmar{T}(; period=252)

Calculate the Calmar ratio from a stream of periodic returns.

The Calmar ratio measures risk-adjusted performance by dividing the annualized return by the absolute value of the maximum drawdown.

Mathematical Definition

$\text{Calmar} = \frac{\text{AnnualizedReturn}}{|\text{MaxDrawDown}|}$

Where:

  • AnnualizedReturn is the CAGR (Compound Annual Growth Rate)
  • MaxDrawDown is the worst peak-to-trough decline (negative value)

Parameters

  • period: Annualization factor (default 252 for daily returns)
    • Daily: 252 (trading days per year)
    • Weekly: 52
    • Monthly: 12

Fields

  • value::T: Current Calmar ratio
  • n::Int: Number of observations
  • annualized_return::AnnualizedReturn{T}: Internal annualized return tracker
  • max_drawdown::MaxDrawDown{T}: Internal max drawdown tracker
  • period::Int: Annualization factor

Edge Cases

  • Returns Inf when max drawdown is zero (all positive returns)
  • Returns 0.0 when no observations have been made

Example

stat = Calmar()
fit!(stat, 0.05)   # 5% gain
fit!(stat, -0.03)  # 3% loss
fit!(stat, 0.02)   # 2% gain
value(stat)        # Calmar ratio

See also: AnnualizedReturn, MaxDrawDown, Sharpe

source

Beta

OnlinePortfolioAnalytics.BetaType
mutable struct Beta{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
Beta{T}()

Calculate the beta coefficient (systematic risk) from paired asset/market returns.

Beta measures how an asset moves relative to a market benchmark. A beta of 1.0 means the asset moves with the market; beta > 1 means more volatile than market; beta < 1 means less volatile; negative beta means inverse correlation.

Mathematical Definition

$\beta = \frac{\text{Cov}(R_a, R_m)}{\text{Var}(R_m)}$

Where:

  • $R_a$ = asset returns
  • $R_m$ = market returns
  • Cov = covariance
  • Var = variance

Input Type

Accepts AssetBenchmarkReturn observations via fit!.

Edge Cases

  • Returns 0.0 when fewer than 2 observations (insufficient data)
  • Returns 0.0 when market variance is zero (avoid division by zero)

Fields

  • value::T: Current beta value
  • n::Int: Number of observations
  • cov_matrix::CovMatrix: Internal 2x2 covariance matrix tracker

Example

stat = Beta()
fit!(stat, AssetBenchmarkReturn(0.05, 0.03))  # Asset +5%, Market +3%
fit!(stat, AssetBenchmarkReturn(0.02, 0.01))  # Asset +2%, Market +1%
fit!(stat, AssetBenchmarkReturn(-0.01, -0.02)) # Asset -1%, Market -2%
value(stat)  # Beta coefficient

See also: AssetBenchmarkReturn, ExpectedReturn

source

Expected return (CAPM)

OnlinePortfolioAnalytics.ExpectedReturnType
mutable struct ExpectedReturn{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
ExpectedReturn{T}(; risk_free=0.0)

Calculate the CAPM (Capital Asset Pricing Model) expected return from paired asset/market returns.

The expected return represents the theoretical return an asset should earn based on its systematic risk (beta) relative to the market.

Mathematical Definition

$E[R_a] = r_f + \beta \times (E[R_m] - r_f)$

Where:

  • $E[R_a]$ = expected return of the asset
  • $r_f$ = risk-free rate
  • $\beta$ = beta coefficient (systematic risk)
  • $E[R_m]$ = expected market return (mean)

Parameters

  • risk_free: Risk-free rate of return (default 0.0)

Input Type

Accepts AssetBenchmarkReturn observations via fit!.

Edge Cases

  • Returns risk_free when fewer than 2 observations (insufficient data for beta)

Fields

  • value::T: Current expected return
  • n::Int: Number of observations
  • beta::Beta{T}: Internal beta tracker
  • risk_free::T: Risk-free rate

Example

stat = ExpectedReturn(risk_free=0.02)  # 2% risk-free rate
fit!(stat, AssetBenchmarkReturn(0.05, 0.03))  # Asset +5%, Market +3%
fit!(stat, AssetBenchmarkReturn(0.02, 0.01))  # Asset +2%, Market +1%
value(stat)  # CAPM expected return

See also: AssetBenchmarkReturn, Beta

source

Value at Risk (VaR)

OnlinePortfolioAnalytics.VaRType
mutable struct VaR{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
VaR{T}(; confidence=0.95, b=500)

Calculate Value at Risk (VaR) from a stream of returns using online quantile estimation.

VaR measures the potential loss at a given confidence level. For example, a 95% VaR of -0.05 means there is a 5% chance of losing more than 5% of the portfolio value.

Mathematical Definition

$\text{VaR}_\alpha = \text{Quantile}_{1-\alpha}(R)$

Where:

  • $\alpha$ = confidence level (e.g., 0.95 for 95% VaR)
  • $R$ = return distribution
  • The result is the $(1-\alpha)$ percentile of returns

Parameters

  • confidence: Confidence level (default 0.95 for 95% VaR)
  • b: Number of histogram bins for quantile estimation (default 500)

Input Type

Accepts single return values (Number) via fit!.

Edge Cases

  • Returns 0.0 when no observations (n=0)

Fields

  • value::T: Current VaR value
  • n::Int: Number of observations
  • quantile::Quantile: Internal quantile tracker
  • confidence::Float64: Confidence level

Example

stat = VaR(confidence=0.95)
for ret in returns
    fit!(stat, ret)
end
var_95 = value(stat)  # 5th percentile loss

See also: ExpectedShortfall

source

Expected Shortfall (CVaR)

OnlinePortfolioAnalytics.ExpectedShortfallType
mutable struct ExpectedShortfall{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
ExpectedShortfall{T}(; confidence=0.95)

Calculate Expected Shortfall (CVaR/ES) from a stream of returns.

Expected Shortfall measures the average loss in the tail beyond the VaR threshold. Also known as Conditional VaR (CVaR) or Average Value at Risk (AVaR). It is considered a more coherent risk measure than VaR.

Mathematical Definition

$\text{ES}_\alpha = E[R | R \leq \text{VaR}_\alpha]$

Where:

  • $\alpha$ = confidence level (e.g., 0.95 for 95% ES)
  • $R$ = return distribution
  • ES is the conditional expectation of returns below VaR

Parameters

  • confidence: Confidence level (default 0.95 for 95% ES)

Input Type

Accepts single return values (Number) via fit!.

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns VaR value when no observations below threshold

Fields

  • value::T: Current ES value
  • n::Int: Number of observations
  • sum_below::T: Sum of returns at or below VaR threshold
  • count_below::Int: Count of returns at or below VaR
  • var_threshold::T: Current VaR estimate used as threshold
  • confidence::Float64: Confidence level

Example

stat = ExpectedShortfall(confidence=0.95)
for ret in returns
    fit!(stat, ret)
end
es_95 = value(stat)  # Average of worst 5% returns

See also: VaR

source

Treynor ratio

OnlinePortfolioAnalytics.TreynorType
mutable struct Treynor{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
Treynor{T}(; risk_free=0.0)

Calculate Treynor Ratio from paired asset/market returns.

Treynor Ratio measures the excess return per unit of systematic risk (beta). Unlike Sharpe Ratio which uses total risk, Treynor uses only market-related risk.

Mathematical Definition

$\text{Treynor} = \frac{E[R_a] - r_f}{\beta}$

Where:

  • $R_a$ = asset returns
  • $r_f$ = risk-free rate
  • $\beta$ = systematic risk (from CAPM)

Parameters

  • risk_free: Risk-free rate (default 0.0)

Input Type

Accepts AssetBenchmarkReturn observations via fit!.

Edge Cases

  • Returns 0.0 when fewer than 2 observations (insufficient for beta)
  • Returns Inf or -Inf when beta is zero (division by zero)

Fields

  • value::T: Current Treynor ratio
  • n::Int: Number of observations
  • beta::Beta{T}: Internal beta tracker
  • asset_mean::Mean: Mean asset return tracker
  • risk_free::T: Risk-free rate

Example

stat = Treynor(risk_free=0.02)
fit!(stat, AssetBenchmarkReturn(0.05, 0.03))  # Asset +5%, Market +3%
fit!(stat, AssetBenchmarkReturn(0.02, 0.01))  # Asset +2%, Market +1%
value(stat)  # (mean_return - rf) / beta

See also: AssetBenchmarkReturn, Beta, Sharpe

source

Information ratio

OnlinePortfolioAnalytics.InformationRatioType
mutable struct InformationRatio{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
InformationRatio{T}()

Calculate Information Ratio from paired asset/benchmark returns.

Information Ratio measures the excess return of an asset relative to its benchmark, adjusted for the tracking error. It is a key metric for evaluating active management skill.

Mathematical Definition

$\text{IR} = \frac{E[R_a - R_b]}{\sigma(R_a - R_b)} = \frac{\text{Mean Excess Return}}{\text{Tracking Error}}$

Where:

  • $R_a$ = asset/portfolio returns
  • $R_b$ = benchmark returns
  • $E[.]$ = expected value (mean)
  • $\sigma$ = standard deviation

Input Type

Accepts AssetBenchmarkReturn observations via fit!.

Edge Cases

  • Returns 0.0 when fewer than 2 observations (insufficient for TE)
  • Returns 0.0 when tracking error is zero (perfect tracking)

Fields

  • value::T: Current IR value
  • n::Int: Number of observations
  • excess_mean::Mean: Tracker for mean excess return
  • tracking_error::TrackingError{T}: Tracker for tracking error

Example

stat = InformationRatio()
fit!(stat, AssetBenchmarkReturn(0.05, 0.04))  # Asset +5%, Benchmark +4%
fit!(stat, AssetBenchmarkReturn(0.02, 0.03))  # Asset +2%, Benchmark +3%
fit!(stat, AssetBenchmarkReturn(-0.01, -0.02)) # Asset -1%, Benchmark -2%
value(stat)  # Mean(excess) / TrackingError

See also: AssetBenchmarkReturn, TrackingError

source

Tracking error

OnlinePortfolioAnalytics.TrackingErrorType
mutable struct TrackingError{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
TrackingError{T}()

Calculate Tracking Error from paired asset/benchmark returns.

Tracking Error measures how closely a portfolio follows its benchmark by computing the standard deviation of the difference between asset and benchmark returns.

Mathematical Definition

$\text{TE} = \sigma(R_a - R_b)$

Where:

  • $R_a$ = asset/portfolio returns
  • $R_b$ = benchmark returns
  • $\sigma$ = standard deviation

Input Type

Accepts AssetBenchmarkReturn observations via fit!.

Edge Cases

  • Returns 0.0 when fewer than 2 observations (insufficient for std dev)
  • Returns 0.0 for perfect tracking (identical returns)

Fields

  • value::T: Current tracking error value
  • n::Int: Number of observations
  • diff_variance::Variance: Internal variance tracker for return differences

Example

stat = TrackingError()
fit!(stat, AssetBenchmarkReturn(0.05, 0.04))  # Asset +5%, Benchmark +4%
fit!(stat, AssetBenchmarkReturn(0.02, 0.03))  # Asset +2%, Benchmark +3%
fit!(stat, AssetBenchmarkReturn(-0.01, -0.02)) # Asset -1%, Benchmark -2%
value(stat)  # Standard deviation of differences

See also: AssetBenchmarkReturn, InformationRatio

source

Downside deviation

OnlinePortfolioAnalytics.DownsideDeviationType
mutable struct DownsideDeviation{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
DownsideDeviation{T}(; threshold=0.0)

Calculate Downside Deviation (semi-standard deviation) from a stream of returns.

Downside Deviation measures the volatility of returns below a threshold (typically 0 or MAR). It captures only negative volatility, providing a more intuitive measure of risk than symmetric standard deviation.

Mathematical Definition

$\text{DD} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} \min(R_i - \tau, 0)^2}$

Where:

  • $R_i$ = return for period i
  • $\tau$ = threshold (Minimum Acceptable Return)
  • $n$ = total number of observations (consistent with Sortino definition)

Parameters

  • threshold: Minimum Acceptable Return (default 0.0)

Input Type

Accepts single return values (Number) via fit!.

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns 0.0 when all returns are above threshold

Fields

  • value::T: Current downside deviation
  • n::Int: Total observation count
  • n_below::Int: Count of observations below threshold
  • sum_sq_below::T: Sum of squared deviations below threshold
  • threshold::T: MAR threshold

Example

stat = DownsideDeviation(threshold=0.0)
for ret in returns
    fit!(stat, ret)
end
dd = value(stat)  # Semi-std of returns below 0

See also: UpsideDeviation, Sortino

source

Upside deviation

OnlinePortfolioAnalytics.UpsideDeviationType
mutable struct UpsideDeviation{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
UpsideDeviation{T}(; threshold=0.0)

Calculate Upside Deviation (semi-standard deviation) from a stream of returns.

Upside Deviation measures the volatility of returns above a threshold. It captures only positive volatility, complementing Downside Deviation.

Mathematical Definition

$\text{UD} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} \max(R_i - \tau, 0)^2}$

Where:

  • $R_i$ = return for period i
  • $\tau$ = threshold (Minimum Acceptable Return)
  • $n$ = total number of observations

Parameters

  • threshold: Minimum Acceptable Return (default 0.0)

Input Type

Accepts single return values (Number) via fit!.

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns 0.0 when all returns are below threshold

Fields

  • value::T: Current upside deviation
  • n::Int: Total observation count
  • n_above::Int: Count of observations above threshold
  • sum_sq_above::T: Sum of squared deviations above threshold
  • threshold::T: MAR threshold

Example

stat = UpsideDeviation(threshold=0.0)
for ret in returns
    fit!(stat, ret)
end
ud = value(stat)  # Semi-std of returns above 0

See also: DownsideDeviation

source

Omega ratio

OnlinePortfolioAnalytics.OmegaType
mutable struct Omega{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
Omega{T}(; threshold=0.0)

Calculate Omega Ratio from a stream of returns.

Omega Ratio measures the probability-weighted ratio of gains to losses above/below a threshold. It considers the entire return distribution, not just mean and variance.

Mathematical Definition

$\Omega(\tau) = \frac{\sum_{R_i > \tau} (R_i - \tau)}{\sum_{R_i < \tau} (\tau - R_i)}$

Where:

  • $R_i$ = return for period i
  • $\tau$ = threshold (typically 0)

Parameters

  • threshold: Reference threshold (default 0.0)

Input Type

Accepts single return values (Number) via fit!.

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Returns Inf when no losses (all returns above threshold)
  • Returns 0.0 when no gains (all returns below threshold)

Fields

  • value::T: Current Omega ratio
  • n::Int: Observation count
  • sum_gains::T: Sum of returns above threshold
  • sum_losses::T: Sum of absolute shortfall below threshold
  • threshold::T: Reference threshold

Example

stat = Omega(threshold=0.0)
for ret in returns
    fit!(stat, ret)
end
omega = value(stat)  # sum(gains) / sum(losses)

See also: Sharpe, Sortino

source

Jensen's Alpha

OnlinePortfolioAnalytics.JensenAlphaType
mutable struct JensenAlpha{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
JensenAlpha{T}(; risk_free=0.0)

Calculate Jensen's Alpha from paired asset/market returns.

Jensen's Alpha measures the excess return of a portfolio above what the CAPM (Capital Asset Pricing Model) would predict, given its beta. Positive alpha indicates outperformance, negative alpha indicates underperformance.

Mathematical Definition

$\alpha = E[R_a] - (r_f + \beta \times (E[R_m] - r_f))$

Where:

  • $R_a$ = asset returns
  • $R_m$ = market returns
  • $r_f$ = risk-free rate
  • $\beta$ = systematic risk coefficient

Parameters

  • risk_free: Risk-free rate (default 0.0)

Input Type

Accepts AssetBenchmarkReturn observations via fit!.

Edge Cases

  • Returns 0.0 when fewer than 2 observations (insufficient for beta)

Fields

  • value::T: Current Jensen's alpha
  • n::Int: Number of observations
  • asset_mean::Mean: Mean asset return tracker
  • market_mean::Mean: Mean market return tracker
  • beta::Beta{T}: Beta coefficient tracker
  • risk_free::T: Risk-free rate

Example

stat = JensenAlpha(risk_free=0.02)
fit!(stat, AssetBenchmarkReturn(0.05, 0.03))  # Asset +5%, Market +3%
fit!(stat, AssetBenchmarkReturn(0.02, 0.01))  # Asset +2%, Market +1%
value(stat)  # Actual return - CAPM expected return

See also: AssetBenchmarkReturn, Beta, ExpectedReturn

source

Market Capture Ratios

OnlinePortfolioAnalytics.UpCaptureType
mutable struct UpCapture{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
UpCapture{T}()

Calculate up-market capture ratio from paired asset/benchmark returns.

Up capture measures how much of the benchmark's gains the portfolio captures during positive market periods. A ratio > 1.0 means the portfolio outperforms in up markets.

Mathematical Definition

$\text{UpCapture} = \frac{\left(\prod_{R_b > 0}(1 + R_a)\right)^{1/n_{up}} - 1}{\left(\prod_{R_b > 0}(1 + R_b)\right)^{1/n_{up}} - 1}$

Where:

  • $R_a$ = asset return when benchmark is positive
  • $R_b$ = benchmark return (> 0)
  • $n_{up}$ = count of positive benchmark periods

This is the ratio of annualized geometric mean returns in up markets.

Input Type

Accepts AssetBenchmarkReturn observations via fit!. Only observations where benchmark return > 0 are included.

Edge Cases

  • Returns NaN when no positive benchmark periods observed
  • Returns NaN with no observations

Interpretation

  • Ratio > 1.0: Portfolio outperforms benchmark in up markets
  • Ratio = 1.0: Portfolio matches benchmark in up markets
  • Ratio < 1.0: Portfolio underperforms benchmark in up markets

Fields

  • value: Current up capture ratio value

  • n: Total number of observations

  • n_up: Count of up-market observations (benchmark > 0)

  • asset_prod: Product of (1 + R_asset) for up periods

  • benchmark_prod: Product of (1 + R_benchmark) for up periods

Example

stat = UpCapture()
fit!(stat, AssetBenchmarkReturn(0.05, 0.03))  # Up market: +5% vs +3%
fit!(stat, AssetBenchmarkReturn(-0.02, -0.04)) # Down market (ignored)
fit!(stat, AssetBenchmarkReturn(0.02, 0.01))  # Up market: +2% vs +1%
value(stat)  # Up capture ratio (> 1.0 in this case)

See also: DownCapture, UpDownCaptureRatio, AssetBenchmarkReturn

source
OnlinePortfolioAnalytics.DownCaptureType
mutable struct DownCapture{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
DownCapture{T}()

Calculate down-market capture ratio from paired asset/benchmark returns.

Down capture measures how much of the benchmark's losses the portfolio captures during negative market periods. A ratio < 1.0 means the portfolio falls less than the benchmark in down markets, which is desirable.

Mathematical Definition

$\text{DownCapture} = \frac{\left(\prod_{R_b < 0}(1 + R_a)\right)^{1/n_{down}} - 1}{\left(\prod_{R_b < 0}(1 + R_b)\right)^{1/n_{down}} - 1}$

Where:

  • $R_a$ = asset return when benchmark is negative
  • $R_b$ = benchmark return (< 0)
  • $n_{down}$ = count of negative benchmark periods

This is the ratio of annualized geometric mean returns in down markets.

Input Type

Accepts AssetBenchmarkReturn observations via fit!. Only observations where benchmark return < 0 are included.

Edge Cases

  • Returns NaN when no negative benchmark periods observed
  • Returns NaN with no observations

Interpretation

  • Ratio < 1.0: Portfolio falls less than benchmark in down markets (desirable)
  • Ratio = 1.0: Portfolio matches benchmark in down markets
  • Ratio > 1.0: Portfolio falls more than benchmark in down markets (unfavorable)

Fields

  • value: Current down capture ratio value

  • n: Total number of observations

  • n_down: Count of down-market observations (benchmark < 0)

  • asset_prod: Product of (1 + R_asset) for down periods

  • benchmark_prod: Product of (1 + R_benchmark) for down periods

Example

stat = DownCapture()
fit!(stat, AssetBenchmarkReturn(-0.02, -0.05))  # Down market: -2% vs -5%
fit!(stat, AssetBenchmarkReturn(0.03, 0.04))    # Up market (ignored)
fit!(stat, AssetBenchmarkReturn(-0.01, -0.03))  # Down market: -1% vs -3%
value(stat)  # Down capture ratio (< 1.0 in this case - good!)

See also: UpCapture, UpDownCaptureRatio, AssetBenchmarkReturn

source
OnlinePortfolioAnalytics.UpDownCaptureRatioType
mutable struct UpDownCaptureRatio{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
UpDownCaptureRatio{T}()

Calculate the up/down capture ratio from paired asset/benchmark returns.

The up/down capture ratio measures the asymmetry of portfolio performance relative to the benchmark across market conditions. A ratio > 1.0 indicates favorable asymmetry (captures more upside, less downside).

Mathematical Definition

$\text{UpDownCaptureRatio} = \frac{\text{UpCapture}}{\text{DownCapture}}$

Where:

  • UpCapture = geometric mean ratio of returns in up markets
  • DownCapture = geometric mean ratio of returns in down markets

Input Type

Accepts AssetBenchmarkReturn observations via fit!.

Edge Cases

  • Returns NaN when either up capture or down capture is NaN
  • Returns Inf if down capture is zero (undefined in practice)
  • Returns NaN with no observations

Interpretation

  • Ratio > 1.0: Favorable asymmetry (desirable)
    • Portfolio captures more upside and/or less downside
  • Ratio = 1.0: Symmetric performance
  • Ratio < 1.0: Unfavorable asymmetry
    • Portfolio captures less upside and/or more downside

Fields

  • value: Current up/down capture ratio value

  • n: Total number of observations

  • up_capture: Internal up capture tracker

  • down_capture: Internal down capture tracker

Example

stat = UpDownCaptureRatio()
fit!(stat, AssetBenchmarkReturn(0.06, 0.04))   # Up market
fit!(stat, AssetBenchmarkReturn(-0.01, -0.03)) # Down market
fit!(stat, AssetBenchmarkReturn(0.03, 0.02))   # Up market
fit!(stat, AssetBenchmarkReturn(-0.02, -0.04)) # Down market
value(stat)  # Up/Down ratio (> 1.0 means favorable asymmetry)

See also: UpCapture, DownCapture, AssetBenchmarkReturn

source

Extended Risk-Adjusted Ratios

OnlinePortfolioAnalytics.UlcerIndexType
mutable struct UlcerIndex{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
UlcerIndex{T}()

Calculate the Ulcer Index from a stream of returns.

The Ulcer Index measures the depth and duration of drawdowns by computing the root-mean-square (RMS) of all drawdown values. It penalizes both the magnitude and frequency of drawdowns, capturing the "pain" of holding an investment through volatile periods.

Mathematical Definition

$\text{UlcerIndex} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} D_i^2}$

Where:

  • $D_i$ = drawdown at time i (from DrawDowns tracker, always ≤ 0)

Edge Cases

  • Returns 0.0 when no observations
  • Returns 0.0 when no drawdown (always at peak)

Interpretation

  • Lower values indicate smoother returns with shallower drawdowns
  • Higher values indicate more volatile returns with deeper/longer drawdowns
  • Always non-negative (RMS of non-positive values)

Fields

  • drawdowns: Internal drawdown tracker

  • rms: RMS of drawdown values

Example

stat = UlcerIndex()
fit!(stat, 0.10)   # +10% gain - new peak
fit!(stat, -0.05)  # -5% loss - in drawdown
fit!(stat, -0.03)  # -3% loss - deeper drawdown
value(stat)        # RMS of drawdown values

See also: PainIndex, DrawDowns, MaxDrawDown

source
OnlinePortfolioAnalytics.PainIndexType
mutable struct PainIndex{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
PainIndex{T}()

Calculate the Pain Index from a stream of returns.

The Pain Index measures the average depth of drawdowns by computing the mean of absolute drawdown values. It provides a linear measure of "pain" compared to the quadratic penalty of the Ulcer Index.

Mathematical Definition

$\text{PainIndex} = \frac{1}{n} \sum_{i=1}^{n} |D_i|$

Where:

  • $D_i$ = drawdown at time i (from DrawDowns tracker, always ≤ 0)
  • $|D_i|$ = absolute value of drawdown

Edge Cases

  • Returns 0.0 when no observations
  • Returns 0.0 when no drawdown (always at peak)

Interpretation

  • Lower values indicate smoother returns with shallower drawdowns
  • Higher values indicate more volatile returns with deeper drawdowns
  • Always non-negative

Fields

  • value: Current Pain Index value

  • n: Number of observations

  • drawdowns: Internal drawdown tracker

  • sum_abs_dd: Sum of absolute drawdowns

Example

stat = PainIndex()
fit!(stat, 0.10)   # +10% gain - new peak
fit!(stat, -0.05)  # -5% loss - in drawdown
fit!(stat, -0.03)  # -3% loss - deeper drawdown
value(stat)        # Mean of absolute drawdown values

See also: UlcerIndex, PainRatio, DrawDowns

source
OnlinePortfolioAnalytics.SterlingRatioType
mutable struct SterlingRatio{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
SterlingRatio{T}(; period=252, threshold=0.10)

Calculate the Sterling Ratio from a stream of returns.

The Sterling Ratio measures risk-adjusted performance by dividing annualized return by the adjusted maximum drawdown. The threshold (default 10%) accounts for "normal" expected drawdown, making the ratio more stable for portfolios with small drawdowns.

Mathematical Definition

$\text{SterlingRatio} = \frac{\text{AnnualizedReturn}}{|\text{MaxDrawDown}| - \text{threshold}}$

Where:

  • AnnualizedReturn = geometric mean return annualized
  • MaxDrawDown = worst peak-to-trough decline (negative value)
  • threshold = drawdown adjustment (default 0.10)

Parameters

  • period: Annualization factor (default: 252 for daily returns)
  • threshold: Drawdown adjustment (default: 0.10 = 10%)

Edge Cases

  • Returns Inf when |MaxDD| ≤ threshold (adjusted denominator is ≤ 0)
  • Returns 0.0 when no observations

Interpretation

  • Higher values indicate better risk-adjusted returns
  • Accounts for expected "normal" drawdown via threshold

Fields

  • value: Current Sterling Ratio value

  • n: Number of observations

  • annualized_return: Internal annualized return tracker

  • max_drawdown: Internal max drawdown tracker

  • threshold: Drawdown threshold adjustment

  • period: Annualization period

Example

stat = SterlingRatio(period=252, threshold=0.10)
for r in returns
    fit!(stat, r)
end
value(stat)  # Annualized return / (|MaxDD| - 10%)

See also: Calmar, MaxDrawDown, AnnualizedReturn

source
OnlinePortfolioAnalytics.BurkeRatioType
mutable struct BurkeRatio{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
BurkeRatio{T}(; period=252, risk_free=0)

Calculate the Burke Ratio from a stream of returns.

The Burke Ratio measures risk-adjusted performance by dividing excess return by the root-mean-square of drawdown values. Unlike Sterling (which uses only max drawdown), Burke penalizes both the magnitude and frequency of all drawdowns.

Mathematical Definition

$\text{BurkeRatio} = \frac{\text{AnnualizedReturn} - R_f}{\sqrt{\frac{1}{n}\sum_{i=1}^{n} D_i^2}}$

Where:

  • AnnualizedReturn = geometric mean return annualized
  • $R_f$ = risk-free rate
  • $D_i$ = drawdown at time i

The denominator is equivalent to the Ulcer Index.

Parameters

  • period: Annualization factor (default: 252 for daily returns)
  • risk_free: Risk-free rate per period (default: 0)

Edge Cases

  • Returns Inf when sum of squared drawdowns is zero (no drawdowns)
  • Returns 0.0 when no observations

Interpretation

  • Higher values indicate better risk-adjusted returns
  • Penalizes both depth and frequency of drawdowns

Fields

  • value: Current Burke Ratio value

  • n: Number of observations

  • annualized_return: Internal annualized return tracker

  • drawdowns: Internal drawdown tracker

  • sum_dd_squared: Sum of squared drawdowns

  • risk_free: Risk-free rate

  • period: Annualization period

Example

stat = BurkeRatio(period=252, risk_free=0.0)
for r in returns
    fit!(stat, r)
end
value(stat)  # Excess return / sqrt(mean(DD^2))

See also: SterlingRatio, UlcerIndex, MaxDrawDown

source
OnlinePortfolioAnalytics.PainRatioType
mutable struct PainRatio{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
PainRatio{T}(; period=252, risk_free=0)

Calculate the Pain Ratio from a stream of returns.

The Pain Ratio measures risk-adjusted performance by dividing excess return by the Pain Index (mean absolute drawdown). It provides a linear penalty for drawdowns compared to the quadratic penalty of the Burke Ratio.

Mathematical Definition

$\text{PainRatio} = \frac{\text{AnnualizedReturn} - R_f}{\text{PainIndex}}$

Where:

  • AnnualizedReturn = geometric mean return annualized
  • $R_f$ = risk-free rate
  • PainIndex = mean of absolute drawdown values

Parameters

  • period: Annualization factor (default: 252 for daily returns)
  • risk_free: Risk-free rate per period (default: 0)

Edge Cases

  • Returns Inf when Pain Index is zero (no drawdowns)
  • Returns 0.0 when no observations

Interpretation

  • Higher values indicate better risk-adjusted returns
  • Uses linear (not quadratic) penalty for drawdowns

Fields

  • value: Current Pain Ratio value

  • n: Number of observations

  • annualized_return: Internal annualized return tracker

  • pain_index: Internal Pain Index tracker

  • risk_free: Risk-free rate

  • period: Annualization period

Example

stat = PainRatio(period=252, risk_free=0.0)
for r in returns
    fit!(stat, r)
end
value(stat)  # Excess return / PainIndex

See also: PainIndex, BurkeRatio, SterlingRatio

source

Volatility & Stability Metrics

OnlinePortfolioAnalytics.AnnualVolatilityType
mutable struct AnnualVolatility{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
AnnualVolatility{T}(; period=252)

Calculate annualized volatility from a stream of periodic returns.

Annualized volatility is the standard deviation of returns scaled by the square root of the annualization period. It represents the expected annual dispersion of returns.

Mathematical Definition

$\text{Annual Volatility} = \sigma \times \sqrt{\text{period}}$

Where:

  • $\sigma$ = sample standard deviation of periodic returns
  • period = annualization factor (252 for daily, 52 for weekly, 12 for monthly)

Parameters

  • period: Annualization factor (default 252 for daily returns)
    • Daily: 252 (trading days per year)
    • Weekly: 52
    • Monthly: 12

Fields

  • value: Current annualized volatility value

  • n: Number of observations

  • variance: Internal variance tracker

  • period: Annualization period

Example

stat = AnnualVolatility()
fit!(stat, 0.01)   # 1% daily return
fit!(stat, 0.02)   # 2% daily return
fit!(stat, -0.01)  # -1% daily return
value(stat)        # Annualized volatility

See also: StdDev, Sharpe

source
OnlinePortfolioAnalytics.StabilityType
mutable struct Stability{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
Stability{T}()

Calculate stability as the R-squared of a linear regression of cumulative log returns.

Stability measures how consistently returns grow over time. A stability of 1.0 indicates perfectly linear growth (constant returns), while lower values indicate more erratic growth.

Mathematical Definition

Stability is the coefficient of determination (R²) from regressing cumulative log returns on the observation index:

$R^2 = 1 - \frac{SS_{res}}{SS_{tot}}$

Where we track cumulative log returns: $y_i = \sum_{j=1}^{i} \log(1 + r_j)$

And regress against time index $x_i = i$.

Edge Cases

  • Returns 0.0 when fewer than 2 observations (cannot compute regression)
  • Returns values in [0, 1] for valid regressions

Fields

  • value: Current R-squared value

  • n: Number of observations

  • sum_x: Sum of x (time indices)

  • sum_x2: Sum of x squared

  • sum_y: Sum of y (cumulative log returns)

  • sum_y2: Sum of y squared

  • sum_xy: Sum of x*y

  • cum_log_return: Current cumulative log return

Example

stat = Stability()
for _ in 1:20
    fit!(stat, 0.01)  # Consistent 1% return
end
value(stat)  # Should be close to 1.0 (highly stable)

See also: AnnualizedReturn

source
OnlinePortfolioAnalytics.TailRatioType
mutable struct TailRatio{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
TailRatio{T}(; b=500)

Calculate the tail ratio as the ratio of the 95th percentile to the absolute value of the 5th percentile of returns.

Tail ratio measures the symmetry of return distribution tails:

  • Ratio > 1.0: Fatter right tail (larger gains than losses at extremes)
  • Ratio ≈ 1.0: Symmetric tails
  • Ratio < 1.0: Fatter left tail (larger losses than gains at extremes)

Mathematical Definition

$\text{Tail Ratio} = \frac{\text{Percentile}_{95}(R)}{|\text{Percentile}_{5}(R)|}$

Where:

  • $\text{Percentile}_{95}(R)$ = 95th percentile of returns
  • $\text{Percentile}_{5}(R)$ = 5th percentile of returns

Parameters

  • b: Number of histogram bins for quantile estimation (default 500)

Edge Cases

  • Returns Inf if 5th percentile is zero
  • May return NaN with insufficient data

Fields

  • value: Current tail ratio value

  • n: Number of observations

  • quantile: Internal quantile tracker for 5th and 95th percentiles

Example

stat = TailRatio()
for r in returns
    fit!(stat, r)
end
ratio = value(stat)  # > 1.0 means fatter right tail

See also: VaR, ExpectedShortfall

source

Modigliani Measures

OnlinePortfolioAnalytics.M2Type
mutable struct M2{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
M2{T}(; risk_free=0.0)

Calculate the M2 (Modigliani-Modigliani) risk-adjusted performance measure from a stream of paired portfolio and benchmark returns.

M2 adjusts the portfolio return to have the same volatility as the benchmark, making performance comparison between portfolios with different risk levels more meaningful.

Mathematical Definition

$M^2 = R_f + (\bar{R}_{port} - R_f) \times \frac{\sigma_{bench}}{\sigma_{port}}$

Where:

  • $R_f$ = risk-free rate
  • $\bar{R}_{port}$ = mean portfolio return
  • $\sigma_{port}$ = portfolio standard deviation
  • $\sigma_{bench}$ = benchmark standard deviation

Interpretation

  • M2 represents what the portfolio return would have been if it had the same risk as the benchmark
  • Higher M2 indicates better risk-adjusted performance
  • M2 is directly comparable to benchmark return (same scale and units)

Parameters

  • risk_free: Risk-free rate (default 0.0)

Edge Cases

  • Returns 0.0 when portfolio volatility is zero (undefined)
  • Returns 0.0 when fewer than 2 observations (insufficient data)

Fields

  • value: Current M2 value

  • n: Number of observations

  • port_mean: Portfolio mean tracker

  • port_variance: Portfolio variance tracker

  • bench_variance: Benchmark variance tracker

  • risk_free: Risk-free rate

Example

stat = M2(risk_free=0.02)
fit!(stat, AssetBenchmarkReturn(0.10, 0.08))  # Portfolio +10%, Benchmark +8%
fit!(stat, AssetBenchmarkReturn(0.05, 0.04))  # Portfolio +5%, Benchmark +4%
value(stat)  # Risk-adjusted portfolio return

See also: MSquaredExcess, Sharpe, InformationRatio

source
OnlinePortfolioAnalytics.MSquaredExcessType
mutable struct MSquaredExcess{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
MSquaredExcess{T}(; risk_free=0.0)

Calculate the M-Squared Excess (M2 minus benchmark mean return) from a stream of paired portfolio and benchmark returns.

M-Squared Excess represents the risk-adjusted excess return of the portfolio relative to the benchmark. It shows how much the portfolio would have outperformed (or underperformed) the benchmark if both had the same volatility.

Mathematical Definition

$M^2_{excess} = M^2 - \bar{R}_{bench}$

Where:

  • $M^2 = R_f + (\bar{R}_{port} - R_f) \times \frac{\sigma_{bench}}{\sigma_{port}}$
  • $\bar{R}_{bench}$ = mean benchmark return

Interpretation

  • Positive value: Portfolio outperforms on a risk-adjusted basis
  • Negative value: Portfolio underperforms on a risk-adjusted basis
  • Zero: Portfolio performs exactly as expected for its risk level

Parameters

  • risk_free: Risk-free rate (default 0.0)

Edge Cases

  • Returns 0.0 when fewer than 2 observations (insufficient data)

Fields

  • value: Current M-Squared Excess value

  • n: Number of observations

  • m2: Internal M2 tracker

  • bench_mean: Benchmark mean tracker

  • risk_free: Risk-free rate

Example

stat = MSquaredExcess(risk_free=0.02)
fit!(stat, AssetBenchmarkReturn(0.10, 0.08))
fit!(stat, AssetBenchmarkReturn(0.05, 0.04))
value(stat)  # Risk-adjusted excess return vs benchmark

See also: M2, InformationRatio, ActivePremium

source
OnlinePortfolioAnalytics.ActivePremiumType
mutable struct ActivePremium{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{AssetBenchmarkReturn{T}}
ActivePremium{T}(; period=252)

Calculate the Active Premium (annualized portfolio return minus annualized benchmark return) from a stream of paired portfolio and benchmark returns.

Active Premium measures the raw excess return of the portfolio over the benchmark on an annualized basis, without adjusting for risk.

Mathematical Definition

$\text{Active Premium} = \text{AnnualizedReturn}_{port} - \text{AnnualizedReturn}_{bench}$

Where AnnualizedReturn is the CAGR (Compound Annual Growth Rate): $\text{AnnualizedReturn} = (\prod_{i=1}^{n}(1 + r_i))^{period/n} - 1$

Interpretation

  • Positive value: Portfolio outperforms benchmark
  • Negative value: Portfolio underperforms benchmark
  • Zero: Portfolio matches benchmark exactly

Parameters

  • period: Annualization factor (default 252 for daily returns)
    • Daily: 252 (trading days per year)
    • Weekly: 52
    • Monthly: 12

Fields

  • value: Current Active Premium value

  • n: Number of observations

  • port_ann_return: Portfolio annualized return tracker

  • bench_ann_return: Benchmark annualized return tracker

  • period: Annualization period

Example

stat = ActivePremium(period=252)
fit!(stat, AssetBenchmarkReturn(0.01, 0.008))  # Daily returns
fit!(stat, AssetBenchmarkReturn(0.02, 0.015))
value(stat)  # Annualized excess return

See also: AnnualizedReturn, InformationRatio, MSquaredExcess

source

Upside Potential Ratio

OnlinePortfolioAnalytics.UpsidePotentialRatioType
mutable struct UpsidePotentialRatio{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
UpsidePotentialRatio{T}(; mar=0.0)

Calculate the Upside Potential Ratio from a stream of returns.

The Upside Potential Ratio measures the ratio of expected positive deviation above a Minimum Acceptable Return (MAR) to the downside deviation below that threshold. It captures the asymmetry between upside gains and downside losses.

Mathematical Definition

$\text{UPR} = \frac{E[\max(R - MAR, 0)]}{\text{DownsideDeviation}}$

Where:

  • $R$ = return
  • $MAR$ = Minimum Acceptable Return (threshold)
  • Upside Potential = $\frac{1}{n} \sum_{i=1}^{n} \max(R_i - MAR, 0)$
  • Downside Deviation = $\sqrt{\frac{1}{n} \sum_{i=1}^{n} \min(R_i - MAR, 0)^2}$

Interpretation

  • UPR > 1: Upside potential exceeds downside risk (favorable)
  • UPR = 1: Upside potential equals downside risk
  • UPR < 1: Downside risk exceeds upside potential (unfavorable)
  • UPR = Inf: No downside (all returns above MAR)
  • UPR = 0: No upside (all returns below MAR)

Parameters

  • mar: Minimum Acceptable Return threshold (default 0.0)

Fields

  • value: Current Upside Potential Ratio value

  • n: Number of observations

  • sum_upside: Sum of positive deviations from MAR

  • downside_deviation: Internal downside deviation tracker

  • mar: Minimum Acceptable Return threshold

Example

stat = UpsidePotentialRatio(mar=0.0)
fit!(stat, 0.10)   # +10% return
fit!(stat, -0.03)  # -3% return
fit!(stat, 0.05)   # +5% return
value(stat)  # Upside potential / downside deviation

See also: DownsideDeviation, UpsideDeviation, Sortino

source

Rolling Window Framework

OnlinePortfolioAnalytics.RollingType
mutable struct Rolling{T, S<:OnlineStatsBase.OnlineStat} <: OnlineStatsBase.OnlineStat{T}
Rolling(stat; window)

Wrap any OnlineStat to compute rolling window statistics.

The Rolling wrapper maintains a circular buffer of observations and recomputes the wrapped statistic over only the most recent window observations. This enables streaming computation of rolling metrics like rolling Sharpe ratio or rolling drawdown.

Parameters

  • stat: Any OnlineStat to wrap (e.g., Sharpe{Float64}(), MaxDrawDown{Float64}())
  • window: Size of the rolling window (must be > 0)

Implementation Details

When a new observation arrives:

  1. Add it to the circular buffer
  2. If buffer exceeds window size, the oldest observation is automatically removed
  3. Reset the wrapped stat and refit with all buffer contents

Edge Cases

  • Before window is full: Computes on available observations (partial window)
  • After window is full: Computes on exactly window most recent observations

Fields

  • stat: The wrapped OnlineStat

  • buffer: Circular buffer storing observations (OnlineStatsBase.CircBuff)

  • window: Rolling window size

  • n: Total observations seen

Example

# Rolling 60-period Sharpe ratio
rolling_sharpe = Rolling(Sharpe{Float64}(), window=60)
for ret in daily_returns
    fit!(rolling_sharpe, ret)
    println("60-day rolling Sharpe: ", value(rolling_sharpe))
end

# Rolling 30-period max drawdown
rolling_dd = Rolling(MaxDrawDown{Float64}(), window=30)
for ret in returns
    fit!(rolling_dd, ret)
end

See also: Sharpe, MaxDrawDown, Calmar

source

Input types

Asset/Benchmark return pair

OnlinePortfolioAnalytics.AssetBenchmarkReturnType
struct AssetBenchmarkReturn{T<:Real}
AssetBenchmarkReturn{T<:Real}(asset, benchmark)

Wrapper type for paired (asset, benchmark) return observations.

Used as input for relative performance metrics (e.g., TrackingError, InformationRatio) and CAPM-based metrics (e.g., Beta, ExpectedReturn, Treynor, JensenAlpha).

The benchmark can be any reference portfolio or market index depending on the analysis context.

Fields

  • asset::T: Asset/portfolio return for this observation
  • benchmark::T: Benchmark/market return for this observation

Example

obs = AssetBenchmarkReturn(0.05, 0.03)  # 5% asset return, 3% benchmark return
fit!(beta_stat, obs)
fit!(tracking_error_stat, obs)

See also: Beta, ExpectedReturn, Treynor, JensenAlpha, TrackingError, InformationRatio

source

Other

OnlinePortfolioAnalytics.ProdType
mutable struct Prod{T} <: OnlineStatsBase.OnlineStat{Number}
Prod(T::Type = Float64)

Streaming product accumulator that computes the running product of observations.

Mathematical Definition

$P = \prod_{i=1}^{n} x_i$

Where:

  • $x_i$ = observation for period i
  • $n$ = number of observations

For weighted observations with weight $w$: $P = P \cdot x^w$

This represents "fitting x with multiplicity w" - equivalent to fitting x exactly w times.

Fields

  • prod::T: Current accumulated product value
  • n::Int: Number of observations (or total accumulated weight)

Initial State

  • prod = one(T) (multiplicative identity)
  • n = 0

Edge Cases

  • Empty stat: value(stat) == one(T), nobs(stat) == 0
  • Zero input: Product becomes and stays zero
  • For T<:Integer: inputs are rounded before multiplication

Example

stat = Prod(Float64)
fit!(stat, 2.0)
fit!(stat, 3.0)
fit!(stat, 4.0)
value(stat)  # => 24.0
nobs(stat)   # => 3

# Weighted fit (x^w semantics)
stat2 = Prod(Float64)
fit!(stat2, 2.0, 3)  # 2^3 = 8
value(stat2)  # => 8.0

See also: LogProd, CumulativeReturn, GeometricMeanReturn

source
OnlinePortfolioAnalytics.LogProdType
mutable struct LogProd{T} <: OnlineStatsBase.OnlineStat{Number}
LogProd(T::Type = Float64)

Numerically stable streaming product accumulator that operates in log-space.

For products of many values (>100), standard multiplication can overflow (Inf) or underflow (0.0). LogProd avoids this by accumulating log(x) values and returning exp(sum_of_logs).

Mathematical Definition

$P = \prod_{i=1}^{n} x_i = \exp\left(\sum_{i=1}^{n} \log(x_i)\right)$

For weighted observations: $P = P \cdot x^w = \exp(\text{log\_sum} + w \cdot \log(x))$

Fields

  • log_sum::T: Sum of logarithms of observed values
  • n::Int: Number of observations (or total accumulated weight)

Initial State

  • log_sum = zero(T)
  • n = 0
  • value(stat) == 1.0 (since exp(0) = 1)

Edge Cases

  • Empty stat: value(stat) == 1.0, nobs(stat) == 0
  • Zero input (x = 0): log(0) = -Inf, so value(stat) == 0.0
  • Negative input (x < 0): log(x) returns NaN (undefined in real domain)
  • For very large products: stays finite when Prod would overflow

Example

# Standard Prod overflows
prod_stat = Prod(Float64)
for _ in 1:10000
    fit!(prod_stat, 1.001)
end
value(prod_stat)  # => Inf (overflow!)

# LogProd stays stable
log_stat = LogProd(Float64)
for _ in 1:10000
    fit!(log_stat, 1.001)
end
value(log_stat)  # => 21916.68... (finite and correct)

See also: Prod

source
OnlinePortfolioAnalytics.RMSType
mutable struct RMS{T} <: OnlinePortfolioAnalytics.PortfolioAnalyticsSingleOutput{T}
RMS{T}()

Calculate the Root Mean Square (RMS) from a stream of numeric values.

RMS is a fundamental statistical measure that computes the square root of the mean of squared values. It is commonly used in signal processing, physics, and finance to measure the magnitude of varying quantities.

Mathematical Definition

$\text{RMS} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} x_i^2}$

Where:

  • $x_i$ = observation at time i
  • $n$ = total number of observations

Edge Cases

  • Returns 0.0 when no observations (n=0)
  • Handles negative values correctly (squared, so sign doesn't matter)
  • RMS of all zeros returns 0.0

Fields

  • value: Current RMS value

  • n: Number of observations

  • sum_sq: Sum of squared values

Example

stat = RMS()
fit!(stat, 3.0)
fit!(stat, 4.0)
value(stat)  # sqrt((9+16)/2) ≈ 3.536

Usage in Portfolio Analytics

RMS is used internally by UlcerIndex to compute the root-mean-square of drawdown values, measuring the "pain" of holding an investment through volatile periods.

See also: UlcerIndex, DownsideDeviation, StdDev

source