跳转至

Metrics Reference

Return, risk, drawdown, trade, and factor evaluation metrics.

Back to API Reference

Inputs are periodic simple returns, with an explicit positive integer periods for annualization. The caller owns cash-flow adjustment, valuation currency, calendar alignment, and coverage. simple_returns does not forward-fill missing prices. For APIs with nan_policy, propagate keeps scalar results unavailable if a required observation is missing, and cumulative curves stay unavailable from the first gap onward. drop describes the observed sample; zero is an explicit modeling assumption, not evidence of a zero return. These policies reject infinite input observations. Undefined analytic results may be NaN; JSON adapters must use null.

Risk dispersion uses sample standard deviation (ddof=1). The current risk-free-rate convention is nominal annual rf / periods; Sortino's required is a separate per-period target. Drawdown values in this API are nonpositive; dashboards showing loss magnitudes convert the sign.

Portfolio and factor metrics.

cash_flow_return

cash_flow_return(begin, finish, *, net_flow=None, events=(), start=None, end=None, method='end_of_day')

Positive flow denotes a deposit; Modified Dietz is an approximation.

Callers must establish completeness, currency and account identity. Event timestamps and valuation endpoints must be timezone-aware actual instants.

autocorrelation

autocorrelation(factor: Series, lag: int = 1, nan_policy: NanPolicy = 'drop') -> pd.Series

Compute lagged factor rank autocorrelation by date.

Parameters

factor : pandas.Series Factor values indexed by (date, symbol). lag : int, default 1 Number of date observations to lag. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing rows are handled.

Returns

pandas.Series Cross-sectional rank autocorrelation by date.

Examples

import pandas as pd idx = pd.MultiIndex.from_product( ... [pd.to_datetime(["2024-01-01", "2024-01-02"]), ["A", "B"]], ... names=["date", "symbol"], ... ) autocorrelation(pd.Series([1, 2, 1, 2], idx)).round(4).tolist() [1.0]

factor_returns

factor_returns(factor: Series, prices: Series, quantiles: int = 5, nan_policy: NanPolicy = 'drop') -> pd.DataFrame

Compute quantile forward returns from prices.

Parameters

factor : pandas.Series Factor values indexed by (date, symbol). prices : pandas.Series Prices indexed by (date, symbol). quantiles : int, default 5 Number of date-level factor quantiles. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing aligned rows are handled.

Returns

pandas.DataFrame Mean next-period returns by date and factor quantile.

Examples

import pandas as pd idx = pd.MultiIndex.from_product( ... [pd.to_datetime(["2024-01-01", "2024-01-02"]), ["A", "B"]], ... names=["date", "symbol"], ... ) out = factor_returns(pd.Series([1, 2], idx[:2]), pd.Series([100, 100, 110, 90], idx), 2) out.round(4).to_dict("list")

ic

ic(factor: Series, forward_returns: Series, nan_policy: NanPolicy = 'drop', groupby: Series | None = None, by_group: bool = False) -> pd.Series

Compute per-date Pearson information coefficient.

Parameters

factor : pandas.Series Factor values indexed by (date, symbol). forward_returns : pandas.Series Forward returns indexed by (date, symbol). nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing aligned rows are handled.

Returns

pandas.Series Pearson correlation by date.

Examples

import pandas as pd idx = pd.MultiIndex.from_product( ... [pd.to_datetime(["2024-01-01"]), ["A", "B", "C"]], ... names=["date", "symbol"], ... ) ic(pd.Series([1, 2, 3], idx), pd.Series([0.1, 0.2, 0.3], idx)).tolist() [1.0]

ic_ir

ic_ir(ic_series: Series, periods: int, nan_policy: NanPolicy = 'drop') -> float

Annualized information coefficient information ratio.

Parameters

ic_series : pandas.Series Information coefficient values through time. periods : int Periods per year. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing IC values are handled.

Returns

float Annualized IC mean divided by sample standard deviation.

Examples

import pandas as pd round(ic_ir(pd.Series([0.10, 0.20, -0.05, 0.15]), periods=12), 4) 3.2071

quantile_returns

quantile_returns(factor: Series, forward_returns: Series, quantiles: int = 5, nan_policy: NanPolicy = 'drop', groupby: Series | None = None, group_neutral: bool = False) -> pd.DataFrame

Compute mean forward returns by factor quantile.

Parameters

factor : pandas.Series Factor values indexed by (date, symbol). forward_returns : pandas.Series Forward returns indexed by (date, symbol). quantiles : int, default 5 Number of date-level factor quantiles. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing aligned rows are handled.

Returns

pandas.DataFrame Mean forward return by date and quantile. Quantiles are 1-based.

Examples

import pandas as pd idx = pd.MultiIndex.from_product( ... [pd.to_datetime(["2024-01-01"]), ["A", "B"]], ... names=["date", "symbol"], ... ) out = quantile_returns(pd.Series([1, 2], idx), pd.Series([0.1, -0.1], idx), 2) out.to_dict("list")

quantile_turnover

quantile_turnover(factor_quantile: Series, quantile: int, period: int = 1) -> pd.Series

Return the share of names newly entering quantile after period dates.

rank_ic

rank_ic(factor: Series, forward_returns: Series, nan_policy: NanPolicy = 'drop', groupby: Series | None = None, by_group: bool = False) -> pd.Series

Compute per-date Spearman rank information coefficient.

Parameters

factor : pandas.Series Factor values indexed by (date, symbol). forward_returns : pandas.Series Forward returns indexed by (date, symbol). nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing aligned rows are handled.

Returns

pandas.Series Spearman rank correlation by date.

Examples

import pandas as pd idx = pd.MultiIndex.from_product( ... [pd.to_datetime(["2024-01-01"]), ["A", "B", "C"]], ... names=["date", "symbol"], ... ) rank_ic(pd.Series([1, 2, 3], idx), pd.Series([0.3, 0.2, 0.1], idx)).tolist() [-1.0]

turnover

turnover(factor: Series, lag: int = 1, nan_policy: NanPolicy = 'drop') -> pd.Series

Compute factor rank turnover.

Parameters

factor : pandas.Series Factor values indexed by (date, symbol). lag : int, default 1 Date lag used for rank autocorrelation. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing rows are handled.

Returns

pandas.Series 1 - autocorrelation by date.

Examples

import pandas as pd idx = pd.MultiIndex.from_product( ... [pd.to_datetime(["2024-01-01", "2024-01-02"]), ["A", "B"]], ... names=["date", "symbol"], ... ) turnover(pd.Series([1, 2, 2, 1], idx)).tolist() [2.0]

annual_return

annual_return(returns: Series | DataFrame, periods: int, nan_policy: NanPolicy = 'drop') -> float | pd.Series

Compute compound annual growth rate from periodic simple returns.

Parameters

returns : pandas.Series or pandas.DataFrame Periodic simple returns. periods : int Periods per year. For example, 252 for daily stock returns. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled before calculation.

Returns

float or pandas.Series Annualized compound return.

Examples

import pandas as pd round(annual_return(pd.Series([0.01, 0.02, -0.005, 0.004]), periods=252), 4) 5.1113

cum_returns

cum_returns(returns: Series | DataFrame, starting_value: float = 0.0, nan_policy: NanPolicy = 'zero') -> pd.Series | pd.DataFrame

Compute cumulative returns from simple returns.

Parameters

returns : pandas.Series or pandas.DataFrame Periodic simple returns. starting_value : float, default 0.0 If zero, return cumulative return. Otherwise return an equity curve starting from this value. nan_policy : {"drop", "zero", "propagate", "raise"}, default "zero" How missing returns are handled before compounding.

Returns

pandas.Series or pandas.DataFrame Cumulative returns or equity curve.

Examples

import pandas as pd cum_returns(pd.Series([0.10, -0.05, 0.02])).round(4).tolist() [0.1, 0.045, 0.0659]

excess_returns

excess_returns(returns: Series | DataFrame, rf: float, periods: int) -> pd.Series | pd.DataFrame

Subtract per-period risk-free return from simple returns.

Parameters

returns : pandas.Series or pandas.DataFrame Periodic simple returns. rf : float Annualized risk-free rate. periods : int Periods per year.

Returns

pandas.Series or pandas.DataFrame Excess returns.

Examples

import pandas as pd excess_returns(pd.Series([0.01, 0.02]), rf=0.024, periods=12).round(4).tolist() [0.008, 0.018]

log_to_simple

log_to_simple(log_returns: Series | DataFrame) -> pd.Series | pd.DataFrame

Convert log returns to simple returns.

Parameters

log_returns : pandas.Series or pandas.DataFrame Log returns.

Returns

pandas.Series or pandas.DataFrame Simple returns.

Examples

import math, pandas as pd log_to_simple(pd.Series([0.0, math.log(1.05)])).round(4).tolist() [0.0, 0.05]

simple_returns

simple_returns(prices: Series | DataFrame) -> pd.Series | pd.DataFrame

Compute simple returns from prices.

Parameters

prices : pandas.Series or pandas.DataFrame Price series or wide price frame.

Returns

pandas.Series or pandas.DataFrame Periodic simple returns with the first missing period removed.

Examples

import pandas as pd simple_returns(pd.Series([100.0, 105.0, 102.9])).round(4).tolist() [0.05, -0.02]

alpha

alpha(returns: Series, benchmark: Series, periods: int, rf: float = 0.0, nan_policy: NanPolicy = 'drop') -> float

Annualized alpha to a benchmark.

Parameters

returns : pandas.Series Asset or strategy returns. benchmark : pandas.Series Benchmark returns. periods : int Periods per year. rf : float, default 0.0 Annualized risk-free rate. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing aligned rows are handled.

Returns

float Annualized intercept.

Examples

import pandas as pd round(alpha(pd.Series([0.01, 0.02, 0.03]), pd.Series([0.02, 0.03, 0.04]), 252), 4) -0.9206

beta

beta(returns: Series, benchmark: Series, nan_policy: NanPolicy = 'drop') -> float

Beta to a benchmark.

Parameters

returns : pandas.Series Asset or strategy returns. benchmark : pandas.Series Benchmark returns. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing aligned rows are handled.

Returns

float OLS slope using sample covariance and variance.

Examples

import pandas as pd round(beta(pd.Series([0.01, 0.02, 0.03]), pd.Series([0.02, 0.03, 0.04])), 4) 1.0

calmar

calmar(returns: Series, periods: int, nan_policy: NanPolicy = 'drop') -> float

Calmar ratio.

Parameters

returns : pandas.Series Periodic simple returns. periods : int Periods per year. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Annual return divided by absolute maximum drawdown.

Examples

import pandas as pd round(calmar(pd.Series([0.10, -0.20, 0.05, -0.10]), periods=12), 4) -1.7414

cvar

cvar(returns: Series, cutoff: float = 0.05, nan_policy: NanPolicy = 'drop') -> float

Conditional value at risk.

Parameters

returns : pandas.Series Periodic simple returns. cutoff : float, default 0.05 Lower-tail percentile expressed as a fraction. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Mean return at or below the historical VaR threshold.

Examples

import pandas as pd round(cvar(pd.Series([-0.10, -0.04, -0.01, 0.02, 0.05, 0.09])), 4) -0.1

downside_risk

downside_risk(returns: Series, periods: int, required: float = 0.0, nan_policy: NanPolicy = 'drop') -> float

Annualized downside risk.

Parameters

returns : pandas.Series Periodic simple returns. periods : int Periods per year. required : float, default 0.0 Per-period required return threshold. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Annualized downside deviation.

Examples

import pandas as pd round(downside_risk(pd.Series([0.02, -0.01, -0.03, 0.01]), periods=12), 4) 0.0548

drawdown_series

drawdown_series(returns: Series, nan_policy: NanPolicy = 'zero') -> pd.Series

Compute drawdown at each point in a return series.

Parameters

returns : pandas.Series Periodic simple returns. nan_policy : {"drop", "zero", "propagate", "raise"}, default "zero" How missing returns are handled.

Returns

pandas.Series Drawdown series, where zero means no drawdown.

Examples

import pandas as pd drawdown_series(pd.Series([0.10, -0.20, 0.05])).round(2).tolist() [0.0, -0.2, -0.16]

information_ratio

information_ratio(returns: Series, benchmark: Series, periods: int, nan_policy: NanPolicy = 'drop') -> float

Annualized information ratio.

Parameters

returns : pandas.Series Asset or strategy returns. benchmark : pandas.Series Benchmark returns. periods : int Periods per year. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing aligned rows are handled.

Returns

float Active return divided by tracking error.

Examples

import pandas as pd r = pd.Series([0.01, 0.03, 0.02]) b = pd.Series([0.02, 0.01, 0.02]) round(information_ratio(r, b, 252), 4) 3.4641

max_drawdown

max_drawdown(returns: Series, nan_policy: NanPolicy = 'zero') -> float

Maximum drawdown.

Parameters

returns : pandas.Series Periodic simple returns. nan_policy : {"drop", "zero", "propagate", "raise"}, default "zero" How missing returns are handled.

Returns

float Most negative drawdown.

Examples

import pandas as pd round(max_drawdown(pd.Series([0.10, -0.20, 0.05, -0.10])), 4) -0.244

omega

omega(returns: Series, threshold: float = 0.0, periods: int = 252, nan_policy: NanPolicy = 'drop') -> float

Omega gain/loss ratio.

Parameters

returns : pandas.Series Periodic simple returns. threshold : float, default 0.0 Annualized return threshold. periods : int, default 252 Periods per year. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Sum of gains divided by absolute sum of losses.

Examples

import pandas as pd round(omega(pd.Series([0.03, 0.01, -0.02, -0.01]), threshold=0.12, periods=12), 4) 0.4

sharpe

sharpe(returns: Series, periods: int, rf: float = 0.0, nan_policy: NanPolicy = 'drop') -> float

Annualized Sharpe ratio.

Parameters

returns : pandas.Series Periodic simple returns. periods : int Periods per year. rf : float, default 0.0 Annualized risk-free rate. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Annualized Sharpe ratio.

Examples

import pandas as pd round(sharpe(pd.Series([0.01, 0.02, -0.01, 0.0]), periods=252), 4) 6.1482

sortino

sortino(returns: Series, periods: int, rf: float = 0.0, required: float = 0.0, nan_policy: NanPolicy = 'drop') -> float

Annualized Sortino ratio.

Parameters

returns : pandas.Series Periodic simple returns. periods : int Periods per year. rf : float, default 0.0 Annualized risk-free rate. required : float, default 0.0 Per-period downside threshold. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Annualized Sortino ratio.

Examples

import pandas as pd round(sortino(pd.Series([0.02, -0.01, -0.03, 0.01]), periods=12), 4) -0.5477

tail_ratio

tail_ratio(returns: Series, cutoff: float = 0.05, nan_policy: NanPolicy = 'drop') -> float

Right-tail to left-tail ratio.

Parameters

returns : pandas.Series Periodic simple returns. cutoff : float, default 0.05 Tail percentile expressed as a fraction. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Absolute ratio of upper and lower percentiles.

Examples

import pandas as pd round(tail_ratio(pd.Series([-0.10, -0.04, -0.01, 0.02, 0.05, 0.09])), 4) 0.9412

var

var(returns: Series, cutoff: float = 0.05, nan_policy: NanPolicy = 'drop') -> float

Historical value at risk percentile.

Parameters

returns : pandas.Series Periodic simple returns. cutoff : float, default 0.05 Lower-tail percentile expressed as a fraction. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Historical lower-tail percentile.

Examples

import pandas as pd round(var(pd.Series([-0.10, -0.04, -0.01, 0.02, 0.05, 0.09])), 4) -0.085

volatility

volatility(returns: Series, periods: int, nan_policy: NanPolicy = 'drop') -> float

Annualized volatility.

Parameters

returns : pandas.Series Periodic simple returns. periods : int Periods per year. nan_policy : {"drop", "zero", "propagate", "raise"}, default "drop" How missing returns are handled.

Returns

float Sample standard deviation annualized by sqrt(periods).

Examples

import pandas as pd round(volatility(pd.Series([0.01, 0.02, -0.01, 0.0]), periods=252), 4) 0.2049

avg_loss

avg_loss(trades: Series | DataFrame) -> float

Compute average losing trade PnL.

Parameters

trades : pandas.Series or pandas.DataFrame Trade PnL values, or a frame containing a pnl column.

Returns

float Mean PnL for negative trades.

Examples

import pandas as pd avg_loss(pd.Series([100.0, -50.0, 0.0, -25.0])) -37.5

avg_win

avg_win(trades: Series | DataFrame) -> float

Compute average profitable trade PnL.

Parameters

trades : pandas.Series or pandas.DataFrame Trade PnL values, or a frame containing a pnl column.

Returns

float Mean PnL for positive trades.

Examples

import pandas as pd avg_win(pd.Series([100.0, -50.0, 0.0, 25.0])) 62.5

expectancy

expectancy(trades: Series | DataFrame) -> float

Compute expected PnL per trade.

Parameters

trades : pandas.Series or pandas.DataFrame Trade PnL values, or a frame containing a pnl column.

Returns

float win_rate * avg_win - loss_rate * abs(avg_loss).

Examples

import pandas as pd expectancy(pd.Series([100.0, -50.0, -25.0, 25.0])) 12.5

max_consecutive_losses

max_consecutive_losses(trades: Series | DataFrame) -> int

Compute the longest run of losing trades.

Parameters

trades : pandas.Series or pandas.DataFrame Trade PnL values, or a frame containing a pnl column.

Returns

int Longest consecutive negative-PnL streak.

Examples

import pandas as pd max_consecutive_losses(pd.Series([100.0, -25.0, -10.0, 50.0])) 2

max_consecutive_wins

max_consecutive_wins(trades: Series | DataFrame) -> int

Compute the longest run of profitable trades.

Parameters

trades : pandas.Series or pandas.DataFrame Trade PnL values, or a frame containing a pnl column.

Returns

int Longest consecutive positive-PnL streak.

Examples

import pandas as pd max_consecutive_wins(pd.Series([100.0, 25.0, -10.0, 50.0])) 2

profit_factor

profit_factor(trades: Series | DataFrame) -> float

Compute gross profit divided by absolute gross loss.

Parameters

trades : pandas.Series or pandas.DataFrame Trade PnL values, or a frame containing a pnl column.

Returns

float Sum of wins divided by the absolute sum of losses.

Examples

import pandas as pd round(profit_factor(pd.Series([100.0, -50.0, -25.0, 25.0])), 4) 1.6667

win_rate

win_rate(trades: Series | DataFrame) -> float

Compute the fraction of profitable trades.

Parameters

trades : pandas.Series or pandas.DataFrame Trade PnL values, or a frame containing a pnl column.

Returns

float Positive trade count divided by total trade count.

Examples

import pandas as pd win_rate(pd.Series([100.0, -50.0, 0.0, 25.0])) 0.5

Missing evidence

simple_returns and factor forward returns do not fill missing prices. Under nan_policy="propagate", missing returns remain unknown: scalar statistics return NaN and cumulative curves stay unknown after the first gap. drop and zero remain explicit alternatives; infinite observations are rejected rather than silently interpreted as valid returns. Annualization requires a positive integer period count.