API

finance-calcs exposes calculation functions at the top level and through the .fcalcs namespace on both polars.Expr and polars.Series. Most functions return pl.Expr so they compose naturally inside select, with_columns, and lazy pipelines. A small number of statistical and post-trade helpers take concrete pl.Series or pl.DataFrame inputs because they compute sample-level summaries, extract round trips, or fit extreme-value routines outside the Polars expression engine.

Use this page as the complete public API map. Function signatures below are shown in a compact form; the reference blocks at the end of each section are rendered by yardang/Sphinx from the live docstrings.


Namespace and Windowing

Every expression function can be called directly:

import polars as pl
import finance_calcs as fc

out = df.select(fc.sharpe(pl.col("ret")).alias("sharpe"))

or through the namespace:

out = df.select(pl.col("ret").fcalcs.sharpe().alias("sharpe"))

The same namespace exists on pl.Series for eager one-off checks:

value = returns.fcalcs.sharpe()

Execution and Input Contracts

Expression metrics compose inside select, with_columns, and lazy queries. Return, risk, and tail metrics consume periodic returns, not price levels; use simple_returns or log_returns to derive them from prices. In these metrics, floating-point NaN and Polars null values are equivalent missing observations. Compounding treats missing returns as neutral and statistical aggregations exclude them.

APIs that require sample-level algorithms are deliberately eager:

  • native_adx, native_parabolic_sar, and native_garch11_variance accept numeric sequences and return NumPy arrays. They are native bridges, not Polars expression plugins.

  • GPD fits and bootstrap/regime helpers accept concrete pl.Series values and return scalars, tuples, or materialized series.

  • neutralize, orthogonalize, round-trip extraction, and related post-trade helpers accept concrete pl.DataFrame values.

Keep eager helpers outside lazy-query plans. A future expression-plugin layer must preserve existing results and null semantics before replacing the native bridges.

Across return, risk, alpha, factor, and tail metrics, window= means a rolling row-count window. period= means bucketed calculations over a calendar or custom period. period= accepts:

  • finance_enums.Frequency, such as Frequency.Month

  • aliases accepted by finance_enums.to_frequency(), such as "monthly"

  • Polars dt.truncate() duration strings, such as "1q" or "2w"

  • a precomputed bucket expression, such as pl.col("fiscal_period")

When period is a frequency or duration string, pass date=pl.col("date") so finance-calcs can build the bucket expression.


Returns and Periods

Return functions turn prices into returns, compound return paths, or terminal period returns. They are the base layer for most risk and factor metrics.

Annualized metrics use frequency. It accepts a finance_enums.Frequency, a standard alias such as "daily" or "monthly", or a positive raw number of observations per year. Raw values support intraday and custom trading schedules without assuming market hours.

Function

Use it for

Notes

period_bucket(date, period)

Build a reusable period bucket from dates

Accepts Frequency, aliases, Polars durations, or an existing bucket expression

simple_returns(price)

Arithmetic price returns

Computes price / price.shift(1) - 1

log_returns(price)

Log price returns

Computes log(price / price.shift(1))

cumulative_returns(returns, starting_value=0.0, *, window=None, period=None, date=None)

Compounded return path

Resets inside each rolling window or period bucket

cumulative_return(returns, *, window=None, period=None, date=None)

Terminal compounded return

Produces the final compound return for the sample, window, or bucket

annualized_return(returns, frequency="daily", *, window=None, period=None, date=None)

Annualized geometric return

Uses compound return and non-missing observation count, not elapsed dates

annualized_volatility(returns, frequency="daily", *, window=None, period=None, date=None)

Annualized standard deviation

Scales by observations per year implied by frequency

finance_calcs.period_bucket(date: Expr, period: Frequency | str | Expr) Expr[source]

Return a period bucket expression for date.

period accepts a finance_enums.Frequency, any alias understood by finance_enums.to_frequency(), any Polars duration string accepted by dt.truncate(), or a precomputed bucket expression.

finance_calcs.simple_returns(price: Expr) Expr[source]

Per-period simple return \(p_t / p_{t-1} - 1\).

finance_calcs.log_returns(price: Expr) Expr[source]

Per-period log return \(\log(p_t / p_{t-1})\).

finance_calcs.cumulative_returns(returns: Expr, starting_value: float = 0.0, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Cumulative compounded return.

With window=None returns the cumulative path (1 + r).cumprod() - 1. With window=N returns the compounded return over each trailing N-bar window. With period=..., the cumulative path resets inside each period bucket. Missing observations are neutral for compounding.

finance_calcs.cumulative_return(returns: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Total compounded return.

window=None → scalar terminal compounded return. window=N → rolling compounded return over each trailing N-bar window. period=... → terminal compounded return for each period bucket.

finance_calcs.annualized_return(returns: Expr, *, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised geometric return.

window=None → scalar lifetime CAGR. window=N → rolling CAGR annualised by the observations per year implied by frequency. period=... → CAGR for each period bucket. Annualisation uses the count of non-missing observations, not elapsed calendar time; date is used only to build a period bucket.

finance_calcs.annualized_volatility(returns: Expr, *, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised standard deviation of returns.

window=None → scalar lifetime volatility; window=N → rolling annualised volatility; period=... → volatility for each period bucket.


Risk and Drawdown

Risk metrics operate on return expressions. Scalar risk_free and required_return inputs are annual rates converted geometrically to per-observation rates. Expression inputs are treated as already per-observation.

Function

Use it for

Notes

sharpe(returns, *, risk_free=0.0, frequency="daily", window=None, period=None, date=None)

Annualized Sharpe ratio

Supports scalar annual risk-free rates or per-observation expressions

sortino(returns, *, required_return=0.0, frequency="daily", window=None, period=None, date=None)

Annualized Sortino ratio

Uses downside deviation below the annual hurdle

calmar(returns, *, frequency="daily", window=None, period=None, date=None)

Annualized return / abs(max drawdown)

Uses the same sample/window/period controls

downside_deviation(returns, *, required_return=0.0, frequency="daily", window=None, period=None, date=None)

Annualized semi-deviation

Squares only observations below the annual hurdle

drawdown_series(returns, *, period=None, date=None)

Running drawdown path

Equity curve divided by running peak, including initial 1.0 baseline

max_drawdown(returns, *, window=None, period=None, date=None)

Most negative drawdown

Rolling windows rebase their equity and peak inside each window

value_at_risk(returns, *, tail_probability=0.05, window=None, period=None, date=None)

Historical VaR quantile

Returns the lower-tail return quantile

conditional_value_at_risk(returns, *, tail_probability=0.05, window=None, period=None, date=None)

Historical conditional VaR

Mean return of observations at or below VaR

expected_shortfall(returns, *, tail_probability=0.05, window=None, period=None, date=None)

Historical expected shortfall

Industry synonym for conditional VaR

value_at_risk_parametric(returns, *, tail_probability=0.05, window=None, period=None, date=None)

Gaussian VaR

Supports common probabilities from the built-in z-score table

finance_calcs.sharpe(returns: Expr, *, risk_free: float | Expr = 0.0, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised Sharpe ratio.

Mean excess return divided by its standard deviation, scaled by the square root of observations per year implied by frequency.

risk_free may be a scalar annual rate (converted to per-period geometrically) or a pl.Expr per-period rate column for a time-varying risk-free rate. window=None → scalar lifetime Sharpe; window=N → rolling; period=... → per-bucket.

finance_calcs.sortino(returns: Expr, *, required_return: float | Expr = 0.0, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised Sortino ratio.

required_return may be a scalar annual threshold or a pl.Expr per-observation column. window=None → scalar; window=N → rolling; period=... → per-bucket.

finance_calcs.calmar(returns: Expr, *, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised return divided by the absolute max drawdown.

window=None → scalar; window=N → rolling; period=... → per-bucket.

finance_calcs.downside_deviation(returns: Expr, *, required_return: float | Expr = 0.0, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised semi-deviation below required_return.

required_return may be a scalar annual threshold (converted to per-observation geometrically) or a pl.Expr per-observation column for a time-varying threshold. window=None → scalar; window=N → rolling; period=... → per-bucket.

finance_calcs.drawdown_series(returns: Expr, *, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Per-period drawdown series equity / running_peak - 1.

The running peak includes an initial equity baseline of 1.0.

finance_calcs.max_drawdown(returns: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Maximum (most negative) drawdown.

window=None → lifetime; window=N → maximum drawdown rebased inside each trailing N-bar window. period=... → maximum drawdown inside each period bucket.

finance_calcs.value_at_risk(returns: Expr, *, tail_probability: float = 0.05, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Historical Value-at-Risk.

window=None → scalar lower-tail quantile; window=N → rolling historical VaR. period=... → per-bucket VaR.

finance_calcs.conditional_value_at_risk(returns: Expr, *, tail_probability: float = 0.05, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Historical CVaR / Expected Shortfall.

window=None → scalar; window=N → rolling mean of returns at or below the rolling VaR. period=... → per-bucket CVaR.

finance_calcs.expected_shortfall(returns: Expr, *, tail_probability: float = 0.05, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Historical expected shortfall, also known as conditional VaR.

finance_calcs.value_at_risk_parametric(returns: Expr, *, tail_probability: float = 0.05, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Gaussian (parametric) VaR \(\mu + \sigma \Phi^{-1}(p)\).

tail_probability must be one of {0.01, 0.025, 0.05, 0.1}.


Report Metrics

These metrics provide the calculation layer for static, terminal, and notebook reports. Expression metrics remain lazy-query compatible. drawdown_details is eager because it returns one row per variable-length drawdown episode.

Function

Use it for

Notes

best_return(returns, *, period=None, date=None)

Highest raw or compounded period return

Canonical best-return metric

worst_return(returns, *, period=None, date=None)

Lowest raw or compounded period return

Canonical worst-return metric

average_win(returns)

Mean positive return

Positive observations only

average_loss(returns)

Mean negative return

Negative observations only

gain_to_pain_ratio(returns)

Net return per unit of summed loss

Uses arithmetic return sums

recovery_factor(returns)

Net return relative to maximum drawdown

Uses absolute arithmetic net return and drawdown

kelly_criterion(returns)

Estimated Kelly allocation fraction

Zero returns are excluded from active-period win rate

drawdown_details(returns, *, date=None)

Materialized drawdown episodes

Returns start, valley, end, duration, depth, and recovery

finance_calcs.best_return(returns: Expr, *, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Highest raw or compounded period return.

finance_calcs.worst_return(returns: Expr, *, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Lowest raw or compounded period return.

finance_calcs.average_win(returns: Expr) Expr[source]

Mean positive return.

finance_calcs.average_loss(returns: Expr) Expr[source]

Mean negative return, expressed as a negative value.

finance_calcs.gain_to_pain_ratio(returns: Expr) Expr[source]

Arithmetic net return divided by absolute summed losses.

finance_calcs.recovery_factor(returns: Expr) Expr[source]

Absolute arithmetic net return divided by absolute maximum drawdown.

finance_calcs.kelly_criterion(returns: Expr) Expr[source]

Kelly fraction estimated from active-period win rate and payoff ratio.

finance_calcs.drawdown_details(returns: Series, *, date: Series | None = None) DataFrame[source]

Return peak, valley, recovery, duration, and depth for each drawdown.

end is null and recovered is false for an open drawdown. Without a date series, integer row positions identify each point.


Overlap and Price Channels

Overlap studies smooth prices or build price channels from high/low/close data. window is an observation lookback, not a calendar bucket.

Function

Use it for

Notes

sma(close, window=20)

Simple moving average

Rolling mean

ema(close, window=20)

Exponential moving average

Uses Polars EWM mean with span=window

wma(close, window=20)

Weighted moving average

Recent observations receive larger linear weights

dema(close, window=20)

Double EMA

2 * EMA - EMA(EMA)

tema(close, window=20)

Triple EMA

3*EMA - 3*EMA(EMA) + EMA(EMA(EMA))

midpoint(close, window=14)

Midpoint of rolling high/low close

Uses close-only rolling max/min

midprice(high, low, window=14)

Midpoint of high/low channel

Uses rolling high max and low min

bbands_upper(close, window=20, upper_deviations=2.0)

Bollinger upper band

Middle plus standard-deviation multiple

bbands_middle(close, window=20)

Bollinger middle band

SMA

bbands_lower(close, window=20, lower_deviations=2.0)

Bollinger lower band

Middle minus standard-deviation multiple

donchian_upper(high, window=20)

Donchian upper channel

Rolling high maximum

donchian_lower(low, window=20)

Donchian lower channel

Rolling low minimum

donchian_middle(high, low, window=20)

Donchian midline

Average of upper and lower channels

finance_calcs.sma(close: Expr, window: int = 20) Expr[source]

Simple moving average over window observations.

Parameters:
  • close – Price (or any series) to average.

  • window – Window length.

Returns:

Rolling mean expression.

finance_calcs.ema(close: Expr, window: int = 20) Expr[source]

Exponential moving average with span = window.

Parameters:
  • close – Series to smooth.

  • window – Span. The smoothing factor is 2 / (window + 1).

Returns:

EWMA expression.

finance_calcs.wma(close: Expr, window: int = 20) Expr[source]

Linearly-weighted moving average.

Parameters:
  • close – Series to smooth.

  • window – Window length.

Returns:

Expression yielding the WMA. Recent observations have higher weight: weight i = i + 1 for i in 0..window-1.

finance_calcs.dema(close: Expr, window: int = 20) Expr[source]

Double exponential moving average: 2 * EMA - EMA(EMA).

Parameters:
  • close – Series to smooth.

  • window – Span.

Returns:

DEMA expression.

finance_calcs.tema(close: Expr, window: int = 20) Expr[source]

Triple exponential moving average 3*EMA - 3*EMA(EMA) + EMA(EMA(EMA)).

Parameters:
  • close – Series to smooth.

  • window – Span.

Returns:

TEMA expression.

finance_calcs.midpoint(close: Expr, window: int = 14) Expr[source]

(rolling_max(close) + rolling_min(close)) / 2.

Parameters:
  • close – Price series.

  • window – Window length.

Returns:

Midpoint expression.

finance_calcs.midprice(high: Expr, low: Expr, window: int = 14) Expr[source]

(rolling_max(high) + rolling_min(low)) / 2.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • window – Window length.

Returns:

Midprice expression.

finance_calcs.bbands_upper(close: Expr, window: int = 20, upper_deviations: float = 2.0) Expr[source]

Bollinger upper band SMA + upper_deviations * std.

Parameters:
  • close – Price series.

  • window – Window length.

  • upper_deviations – Number of standard deviations above the SMA.

Returns:

Upper-band expression.

finance_calcs.bbands_middle(close: Expr, window: int = 20) Expr[source]

Bollinger middle band — SMA of close.

Parameters:
  • close – Price series.

  • window – Window length.

Returns:

Rolling mean expression.

finance_calcs.bbands_lower(close: Expr, window: int = 20, lower_deviations: float = 2.0) Expr[source]

Bollinger lower band SMA - lower_deviations * std.

Parameters:
  • close – Price series.

  • window – Window length.

  • lower_deviations – Number of standard deviations below the SMA.

Returns:

Lower-band expression.

finance_calcs.donchian_upper(high: Expr, window: int = 20) Expr[source]

Donchian upper channel — rolling maximum of high.

Parameters:
  • high – Bar high.

  • window – Window length.

Returns:

Rolling max expression.

finance_calcs.donchian_lower(low: Expr, window: int = 20) Expr[source]

Donchian lower channel — rolling minimum of low.

Parameters:
  • low – Bar low.

  • window – Window length.

Returns:

Rolling min expression.

finance_calcs.donchian_middle(high: Expr, low: Expr, window: int = 20) Expr[source]

Donchian midline.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • window – Window length.

Returns:

Average of the upper and lower Donchian channels.


Momentum

Momentum functions consume close or OHLC expressions and return oscillator, rate-of-change, or directional-movement expressions. window is the observation lookback length.

Function

Use it for

Notes

rsi(close, window=14)

Relative Strength Index

Wilder smoothing

macd_line(close, fast_window=12, slow_window=26)

MACD line

Fast EMA minus slow EMA

macd_signal(close, fast_window=12, slow_window=26, signal_window=9)

MACD signal line

EMA of macd_line

macd_hist(close, fast_window=12, slow_window=26, signal_window=9)

MACD histogram

MACD line minus signal line

mom(close, window=10)

Price momentum

Difference from window observations ago

roc(close, window=10)

Percent rate of change

100 * (close / close.shift(window) - 1)

rocp(close, window=10)

Decimal rate of change

(close - prior) / prior

rocr(close, window=10)

Price ratio

close / prior

rocr100(close, window=10)

Price ratio scaled by 100

100 * rocr

willr(high, low, close, window=14)

Williams %R

Close location within rolling high/low range

stoch_k(high, low, close, window=14)

Fast stochastic %K

Range-normalized close

stoch_d(high, low, close, window=14, signal_window=3)

Stochastic %D

SMA of %K

cci(high, low, close, window=20)

Commodity Channel Index

Typical-price deviation oscillator

cmo(close, window=14)

Chande Momentum Oscillator

Up/down movement balance

trix(close, window=15)

TRIX

One-bar ROC of triple-smoothed log price

plus_dm(high, low)

Raw +DM

Wilder directional movement

minus_dm(high, low)

Raw -DM

Wilder directional movement

plus_di(high, low, close, window=14)

+DI

Smoothed +DM divided by true range

minus_di(high, low, close, window=14)

-DI

Smoothed -DM divided by true range

adx(high, low, close, window=14)

Average Directional Index

Trend-strength measure from +DI and -DI

finance_calcs.rsi(close: Expr, window: int = 14) Expr[source]

Relative Strength Index (Wilder).

Parameters:
  • close – Price series.

  • window – Smoothing window.

Returns:

Expression yielding RSI in [0, 100].

finance_calcs.macd_line(close: Expr, fast_window: int = 12, slow_window: int = 26) Expr[source]

MACD line — EMA(fast) - EMA(slow).

Parameters:
  • close – Price series.

  • fast_window – Fast EMA window.

  • slow_window – Slow EMA window.

Returns:

Expression yielding the MACD line.

finance_calcs.macd_signal(close: Expr, fast_window: int = 12, slow_window: int = 26, signal_window: int = 9) Expr[source]

MACD signal line — EMA of macd_line().

Parameters:
  • close – Price series.

  • fast_window – Fast EMA window.

  • slow_window – Slow EMA window.

  • signal_window – Signal EMA window.

Returns:

Expression yielding the MACD signal line.

finance_calcs.macd_hist(close: Expr, fast_window: int = 12, slow_window: int = 26, signal_window: int = 9) Expr[source]

MACD histogram — MACD - signal.

Parameters:
  • close – Price series.

  • fast_window – Fast EMA window.

  • slow_window – Slow EMA window.

  • signal_window – Signal EMA window.

Returns:

Expression yielding the MACD histogram.

finance_calcs.mom(close: Expr, window: int = 10) Expr[source]

Momentum — close - close[window].

Parameters:
  • close – Price series.

  • window – Look-back length.

Returns:

Difference expression.

finance_calcs.roc(close: Expr, window: int = 10) Expr[source]

Rate-of-change in percent — 100 * (close / close[window] - 1).

Parameters:
  • close – Price series.

  • window – Look-back length.

Returns:

ROC expression.

finance_calcs.rocp(close: Expr, window: int = 10) Expr[source]

ROC percentage (TA-Lib): (close - close[window]) / close[window].

Parameters:
  • close – Price series.

  • window – Look-back length.

Returns:

ROCP expression.

finance_calcs.rocr(close: Expr, window: int = 10) Expr[source]

ROC ratio: close / close[window].

Parameters:
  • close – Price series.

  • window – Look-back length.

Returns:

ROCR expression.

finance_calcs.rocr100(close: Expr, window: int = 10) Expr[source]

ROC ratio scaled by 100.

Parameters:
  • close – Price series.

  • window – Look-back length.

Returns:

ROCR100 expression.

finance_calcs.willr(high: Expr, low: Expr, close: Expr, window: int = 14) Expr[source]

Williams %R.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Window length.

Returns:

Expression in [-100, 0].

finance_calcs.stoch_k(high: Expr, low: Expr, close: Expr, window: int = 14) Expr[source]

Fast stochastic %K.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Window length.

Returns:

Expression in [0, 100].

finance_calcs.stoch_d(high: Expr, low: Expr, close: Expr, window: int = 14, signal_window: int = 3) Expr[source]

Stochastic %D — SMA of stoch_k().

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – %K window length.

  • signal_window – Smoothing window for %D.

Returns:

Expression yielding %D.

finance_calcs.cci(high: Expr, low: Expr, close: Expr, window: int = 20) Expr[source]

Commodity Channel Index.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Window length.

Returns:

CCI expression. Uses mean absolute deviation in the denominator.

finance_calcs.cmo(close: Expr, window: int = 14) Expr[source]

Chande Momentum Oscillator.

Parameters:
  • close – Price series.

  • window – Window length.

Returns:

CMO expression in [-100, 100].

finance_calcs.trix(close: Expr, window: int = 15) Expr[source]

TRIX — 1-day ROC of triple-smoothed log price.

Parameters:
  • close – Price series.

  • window – EMA span.

Returns:

TRIX expression in percent.

finance_calcs.plus_dm(high: Expr, low: Expr) Expr[source]

Wilder’s +DM raw (un-smoothed).

Parameters:
  • high – Bar high.

  • low – Bar low.

Returns:

Per-bar +DM expression. Zero when down-move dominates.

finance_calcs.minus_dm(high: Expr, low: Expr) Expr[source]

Wilder’s -DM raw (un-smoothed).

Parameters:
  • high – Bar high.

  • low – Bar low.

Returns:

Per-bar -DM expression. Zero when up-move dominates.

finance_calcs.plus_di(high: Expr, low: Expr, close: Expr, window: int = 14) Expr[source]

Wilder’s +DI.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Smoothing window.

Returns:

+DI expression in percent.

finance_calcs.minus_di(high: Expr, low: Expr, close: Expr, window: int = 14) Expr[source]

Wilder’s -DI.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Smoothing window.

Returns:

-DI expression in percent.

finance_calcs.adx(high: Expr, low: Expr, close: Expr, window: int = 14) Expr[source]

Average Directional Index (Wilder).

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Smoothing window.

Returns:

ADX expression in [0, 100].


Volatility Indicators

These functions estimate realized or range-based volatility from returns or OHLC bars. window is the observation lookback length.

Function

Use it for

Notes

true_range(high, low, close)

Wilder true range

Max of high-low, high-prior-close, low-prior-close

atr(high, low, close, window=14)

Average True Range

Wilder-smoothed true range

natr(high, low, close, window=14)

Normalized ATR

100 * ATR / close

parkinson_volatility(high, low, window=20, *, frequency="daily")

High-low volatility

Annualized range-based estimator

garman_klass_volatility(open_, high, low, close, window=20, *, frequency="daily")

OHLC volatility

Annualized OHLC estimator

rogers_satchell_volatility(open_, high, low, close, window=20, *, frequency="daily")

Drift-independent OHLC volatility

Annualized; works when drift is nonzero

yang_zhang_volatility(open_, high, low, close, window=20, *, weight=None, frequency="daily")

Overnight + open-close + range volatility

Annualized combination of OHLC variance components

exponentially_weighted_volatility(returns, window=20, *, frequency="daily")

Exponentially weighted volatility

Annualized EWM standard deviation

realized_volatility(returns, window=20, *, frequency="daily")

Rolling realized volatility

Annualized rolling sample standard deviation

finance_calcs.true_range(high: Expr, low: Expr, close: Expr) Expr[source]

Wilder’s true range.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

Returns:

Per-bar TR expression max(H-L, |H - C[-1]|, |L - C[-1]|).

finance_calcs.atr(high: Expr, low: Expr, close: Expr, window: int = 14) Expr[source]

Average True Range using Wilder smoothing.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Smoothing window.

Returns:

ATR expression.

finance_calcs.natr(high: Expr, low: Expr, close: Expr, window: int = 14) Expr[source]

Normalised ATR — 100 * ATR / close.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Smoothing window.

Returns:

NATR expression in percent.

finance_calcs.parkinson_volatility(high: Expr, low: Expr, window: int = 20, *, frequency: Frequency | str | float = Frequency.Day) Expr[source]

Parkinson high-low range volatility estimator.

\[\begin{split}\\hat{\\sigma}^2 = \\frac{1}{4 \\ln 2} \\cdot \\overline{\\left(\\ln(H/L)\\right)^2}\end{split}\]
Parameters:
  • high – Bar high.

  • low – Bar low.

  • window – Window length.

Returns:

Annualized rolling volatility expression.

finance_calcs.garman_klass_volatility(open_: Expr, high: Expr, low: Expr, close: Expr, window: int = 20, *, frequency: Frequency | str | float = Frequency.Day) Expr[source]

Garman-Klass OHLC volatility estimator.

\[\begin{split}\\hat{\\sigma}^2 = \\overline{\\tfrac{1}{2}(\\ln H/L)^2 - (2\\ln 2 - 1)(\\ln C/O)^2}\end{split}\]
Parameters:
  • open – Bar open.

  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Window length.

Returns:

Annualized rolling Garman-Klass volatility expression.

finance_calcs.rogers_satchell_volatility(open_: Expr, high: Expr, low: Expr, close: Expr, window: int = 20, *, frequency: Frequency | str | float = Frequency.Day) Expr[source]

Rogers-Satchell drift-independent volatility.

\[\begin{split}\\hat{\\sigma}^2 = \\overline{\\ln(H/C)\\ln(H/O) + \\ln(L/C)\\ln(L/O)}\end{split}\]
Parameters:
  • open – Bar open.

  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Window length.

Returns:

Annualized rolling Rogers-Satchell volatility expression.

finance_calcs.yang_zhang_volatility(open_: Expr, high: Expr, low: Expr, close: Expr, window: int = 20, *, weight: float | None = None, frequency: Frequency | str | float = Frequency.Day) Expr[source]

Yang-Zhang volatility — minimum-variance combination of overnight, open-to-close, and Rogers-Satchell drift-independent components.

Parameters:
  • open – Bar open.

  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • window – Window length.

  • weight – Weight on open-to-close variance. Defaults to 0.34 / (1.34 + (window+1)/(window-1)).

Returns:

YZ volatility expression (rolling).

finance_calcs.exponentially_weighted_volatility(returns: Expr, window: int = 20, *, frequency: Frequency | str | float = Frequency.Day) Expr[source]

Exponentially weighted standard deviation.

Parameters:
  • returns – Return series.

  • window – EWMA window.

Returns:

Square root of the EWMA variance of returns.

finance_calcs.realized_volatility(returns: Expr, window: int = 20, *, frequency: Frequency | str | float = Frequency.Day) Expr[source]

Rolling realised volatility (sample standard deviation).

Parameters:
  • returns – Return series.

  • window – Window length.

Returns:

Annualized rolling standard deviation expression.


Volume Indicators

Volume indicators combine close movement, intrabar range, and volume into flow or accumulation measures.

Function

Use it for

Notes

obv(close, volume)

On-Balance Volume

Cumulative signed volume based on close direction

ad(high, low, close, volume)

Chaikin Accumulation/Distribution line

Cumulative money-flow volume

adosc(high, low, close, volume, fast_window=3, slow_window=10)

Chaikin A/D Oscillator

Fast EMA of AD minus slow EMA of AD

finance_calcs.obv(close: Expr, volume: Expr) Expr[source]

On-Balance Volume.

Parameters:
  • close – Price series.

  • volume – Volume series.

Returns:

Running cumulative signed volume. The first bar contributes zero because the prior close is unknown.

finance_calcs.ad(high: Expr, low: Expr, close: Expr, volume: Expr) Expr[source]

Chaikin Accumulation/Distribution line.

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • volume – Bar volume.

Returns:

Running A/D line. Bars with zero range contribute zero flow.

finance_calcs.adosc(high: Expr, low: Expr, close: Expr, volume: Expr, fast_window: int = 3, slow_window: int = 10) Expr[source]

Chaikin A/D Oscillator — EMA(AD, fast) - EMA(AD, slow).

Parameters:
  • high – Bar high.

  • low – Bar low.

  • close – Bar close.

  • volume – Bar volume.

  • fast_window – Fast EMA window.

  • slow_window – Slow EMA window.

Returns:

ADOSC expression.


Alpha and Information Coefficient

Alpha helpers are designed for cross-sectional signal panels. Compute forward returns, per-date IC values, and IC summary statistics from generated or real date, symbol, signal, fwd_returns data.

Function

Use it for

Notes

forward_returns(price, horizon=1)

Future simple returns

price.shift(-horizon) / price - 1

information_coefficient(signal, forward_returns, *, method="spearman")

General information coefficient

Selects correlation method explicitly

information_coefficient_pearson(signal, forward_returns)

Linear information coefficient

Pearson correlation

information_coefficient_spearman(signal, forward_returns)

Rank information coefficient

Spearman correlation through ranks

information_coefficient_conditional(signal, forward_returns, condition, *, method="spearman")

Conditional IC

Correlation after filtering observations by a condition

information_coefficient_by_horizon(signal, forward_returns, *, method="spearman")

One-horizon IC

IC against one forward-return horizon

information_coefficient_decay(signal, forward_returns_by_horizon)

IC decay expressions

Builds one aliased IC expression per horizon

information_coefficient_ratio(information_coefficient, *, window=None, period=None, date=None)

IC information ratio

Mean IC divided by IC standard deviation

hit_rate(signal, forward_returns)

Directional hit rate

Fraction where signal and forward-return signs agree

information_coefficient_statistics(information_coefficient)

Series-level IC summary

Returns fully named summary fields

finance_calcs.forward_returns(price: Expr, horizon: int = 1) Expr[source]

Forward simple return over horizon observations.

Parameters:
  • price – Price series.

  • horizon – Look-ahead horizon in observations.

Returns:

Expression yielding price.shift(-horizon) / price - 1.

finance_calcs.information_coefficient(signal: Expr, forward_returns: Expr, *, method: str = 'spearman') Expr[source]

Information coefficient using the requested correlation method.

finance_calcs.information_coefficient_pearson(signal: Expr, forward_returns: Expr) Expr[source]

Pearson information coefficient.

Parameters:
  • signal – Signal / alpha series.

  • forward_returns – Forward-return series of the same length.

Returns:

Scalar correlation expression.

finance_calcs.information_coefficient_spearman(signal: Expr, forward_returns: Expr) Expr[source]

Spearman rank information coefficient.

Parameters:
  • signal – Signal / alpha series.

  • forward_returns – Forward-return series of the same length.

Returns:

Scalar rank-correlation expression.

finance_calcs.information_coefficient_conditional(signal: Expr, forward_returns: Expr, condition: Expr, *, method: str = 'spearman') Expr[source]

Information coefficient on observations matching condition.

finance_calcs.information_coefficient_by_horizon(signal: Expr, forward_returns: Expr, *, method: str = 'spearman') Expr[source]

Information coefficient for one forward-return horizon.

finance_calcs.information_coefficient_decay(signal: Expr, forward_returns_by_horizon: Mapping[int, Expr], *, method: str = 'spearman', prefix: str = 'information_coefficient_') list[Expr][source]

Build one horizon IC expression per forward-return horizon.

finance_calcs.information_coefficient_ratio(information_coefficient: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

IC information ratio — mean(ic) / std(ic).

window=None → scalar; window=N → rolling IR over each trailing N-observation window; period=... → per-bucket IR.

finance_calcs.hit_rate(signal: Expr, forward_returns: Expr) Expr[source]

Fraction of observations where signal and forward-return signs agree.

Parameters:
  • signal – Signal series.

  • forward_returns – Forward return series.

Returns:

Scalar mean expression in [0, 1].

finance_calcs.information_coefficient_statistics(information_coefficient: Series) dict[str, float | int][source]

Summary statistics of an IC time series.

Parameters:

information_coefficient – Information-coefficient time series.

Returns:

Dict with mean, standard deviation, information ratio, t-statistic, positive fraction, and observation count.


Quantile and Signal Transforms

These functions prepare cross-sectional signals for portfolio construction or quantile spread analytics.

Function

Use it for

Notes

assign_quantile(signal, n_quantiles=5)

Cross-sectional quantile labels

Produces integer labels 0..n_quantiles-1

rank_normalize(signal)

Rank-normalized signal

Scales ranks to [-0.5, 0.5]

zscore(signal)

Cross-sectional z-score

Centers and scales by sample standard deviation

winsorize(signal, cutoff=3.0)

Outlier clipping

Clips to mean +/- cutoff * std

long_short_spread(returns, quantile, upper, lower)

Quantile spread return

Mean return of upper quantile minus lower quantile

mean_return_by_quantile(returns, quantile)

Quantile return expressions

Builds one mean-return expression per quantile

quantile_changed(quantile)

Turnover signal

True when quantile label changed from previous row

quantile_turnover(changed)

Quantile turnover

Mean of quantile-change flags

finance_calcs.assign_quantile(signal: Expr, n_quantiles: int = 5) Expr[source]

Assign integer quantile labels 0..n_quantiles-1 to signal.

Parameters:
  • signal – Signal series. Nulls produce null labels.

  • n_quantiles – Number of quantile buckets.

Returns:

Integer expression in [0, n_quantiles - 1]. Higher signal values map to higher labels.

finance_calcs.rank_normalize(signal: Expr) Expr[source]

Cross-sectional rank scaled to [-0.5, 0.5].

Parameters:

signal – Signal series.

Returns:

Expression with mean zero and bounded support.

finance_calcs.zscore(signal: Expr) Expr[source]

Cross-sectional z-score: (x - mean) / std.

Parameters:

signal – Signal series.

Returns:

Z-score expression.

finance_calcs.winsorize(signal: Expr, cutoff: float = 3.0) Expr[source]

Clip values to mean ± cutoff * std.

Parameters:
  • signal – Signal series.

  • cutoff – Number of standard deviations. Must be positive.

Returns:

Clipped expression.

finance_calcs.long_short_spread(returns: Expr, quantile: Expr, upper: int, lower: int) Expr[source]

Top-quantile mean return minus bottom-quantile mean return.

Use inside group_by("date").agg(...):

df.group_by("date").agg(
    long_short_spread(pl.col("ret"), pl.col("q"), upper=4, lower=0)
    .alias("ls"),
)
Parameters:
  • returns – Forward return series.

  • quantile – Integer quantile label series.

  • upper – Long quantile label.

  • lower – Short quantile label.

Returns:

Scalar expression.

finance_calcs.mean_return_by_quantile(returns: Expr, quantile: Expr, *, n_quantiles: int = 5, prefix: str = 'q') list[Expr][source]

Build mean-return expressions for quantile labels 0..n-1.

finance_calcs.quantile_changed(quantile: Expr) Expr[source]

Boolean expression: quantile != quantile.shift(1).

Use inside ... .over("asset") to compute per-asset turnover flags. Aggregate by date to get the fraction of names that changed quantile.

Parameters:

quantile – Integer quantile label series.

Returns:

Boolean expression. The first observation is null/false.

finance_calcs.quantile_turnover(changed: Expr) Expr[source]

Fraction of names whose quantile assignment changed.


Factor and Benchmark Metrics

Factor metrics compare strategy returns against a benchmark return series. They support lifetime, rolling, and period-bucketed calculations where the signature includes window, period, and date.

Function

Use it for

Notes

alpha(returns, benchmark, risk_free=0.0, frequency="daily", *, window=None, period=None, date=None)

Annualized Jensen alpha

Return unexplained by benchmark beta

beta(returns, benchmark, *, window=None, period=None, date=None)

Market beta

cov(returns, benchmark) / var(benchmark)

r_squared(returns, benchmark, *, window=None, period=None, date=None)

Benchmark coefficient of determination

Squared Pearson correlation

up_alpha(...)

Alpha in up markets

Restricts observations to benchmark > 0

down_alpha(...)

Alpha in down markets

Restricts observations to benchmark < 0

up_beta(...)

Beta in up markets

Restricts observations to benchmark > 0

down_beta(...)

Beta in down markets

Restricts observations to benchmark < 0

up_capture(returns, benchmark, *, window=None, period=None, date=None)

Up-market capture

Mean strategy return divided by mean benchmark return when benchmark is positive

down_capture(returns, benchmark, *, window=None, period=None, date=None)

Down-market capture

Mean strategy return divided by mean benchmark return when benchmark is negative

up_down_capture(returns, benchmark, *, window=None, period=None, date=None)

Capture balance

Up capture divided by down capture

batting_average(returns, benchmark, *, window=None, period=None, date=None)

Fraction of outperformance observations

returns > benchmark mean

tracking_error(returns, benchmark, frequency="daily", *, window=None, period=None, date=None)

Annualized active risk

Standard deviation of active return

information_ratio(returns, benchmark, frequency="daily", *, window=None, period=None, date=None)

Annualized active return per active risk

Mean active return divided by active standard deviation, scaled

finance_calcs.alpha(returns: Expr, benchmark: Expr, *, risk_free: float | Expr = 0.0, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised Jensen’s alpha.

risk_free may be a scalar annual rate (divided to per-period) or a pl.Expr per-period rate column for a time-varying risk-free rate. window=None → scalar; window=N → rolling annualised alpha; period=... → per-bucket alpha.

finance_calcs.beta(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

OLS market beta — cov(r, b) / var(b).

window=None → scalar; window=N → rolling beta; period=... → per-bucket beta.

finance_calcs.r_squared(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Coefficient of determination against benchmark returns.

This is squared Pearson correlation. window=None returns a scalar, window=N returns a rolling expression, and period=... computes inside each bucket.

finance_calcs.up_alpha(returns: Expr, benchmark: Expr, *, risk_free: float | Expr = 0.0, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised alpha on up-market bars only.

finance_calcs.down_alpha(returns: Expr, benchmark: Expr, *, risk_free: float | Expr = 0.0, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised alpha on down-market bars only.

finance_calcs.up_beta(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Beta restricted to bars where benchmark > 0.

finance_calcs.down_beta(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Beta restricted to bars where benchmark < 0.

finance_calcs.up_capture(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Mean asset return / mean benchmark return on up-market bars.

finance_calcs.down_capture(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Mean asset return / mean benchmark return on down-market bars.

finance_calcs.up_down_capture(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

up_capture / down_capture.

finance_calcs.batting_average(returns: Expr, benchmark: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Fraction of periods where returns > benchmark.

finance_calcs.tracking_error(returns: Expr, benchmark: Expr, *, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised tracking error scaled by frequency.

finance_calcs.information_ratio(returns: Expr, benchmark: Expr, *, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Annualised information ratio scaled by frequency.


Distribution and Sharpe Statistics

The first five functions are expression metrics. The Sharpe significance and confidence-interval helpers consume a concrete pl.Series because they perform sample-level statistical calculations outside the Polars expression engine.

Function

Use it for

Notes

skewness(returns)

Sample skewness

Expression metric

kurtosis(returns)

Excess kurtosis

Fisher definition

higher_moments(returns)

Bundled higher-moment struct

Fields are skewness and kurtosis

stability_of_timeseries(returns)

Trend stability of cumulative log returns

R-squared of cumulative log returns vs time

common_sense_ratio(returns)

Tail-ratio-adjusted total return sanity check

tail_ratio * (1 + cumulative_return)

sharpe_probability(returns, benchmark_sharpe=0.0, frequency="daily")

Probability Sharpe exceeds benchmark

Probabilistic Sharpe

sharpe_deflated_probability(returns, trial_count, sharpe_variance=None, frequency="daily")

Multiple-testing-adjusted Sharpe probability

Deflated Sharpe probability

sharpe_minimum_track_record_length(returns, benchmark_sharpe=0.0, significance_level=0.05, frequency="daily")

Required sample length

Observations needed for Sharpe confidence

sharpe_bootstrap_confidence_interval(returns, bootstrap_samples=1000, confidence_level=0.95, frequency="daily", seed=None)

Bootstrap Sharpe confidence interval

Returns point estimate, lower, upper

sharpe_confidence_interval(returns, risk_free=0.0, frequency="daily", confidence_level=0.95)

Asymptotic Sharpe confidence interval

Returns point estimate, lower, upper

finance_calcs.skewness(returns: Expr) Expr[source]

Sample skewness of returns.

Parameters:

returns – Returns expression.

Returns:

Scalar skewness.

finance_calcs.kurtosis(returns: Expr) Expr[source]

Excess kurtosis of returns (Fisher definition).

Parameters:

returns – Returns expression.

Returns:

Scalar excess kurtosis.

finance_calcs.higher_moments(returns: Expr) Expr[source]

Bundled struct of skewness and kurtosis for returns.

Parameters:

returns – Returns expression.

Returns:

Struct expression with fields skewness and kurtosis.

finance_calcs.stability_of_timeseries(returns: Expr) Expr[source]

Coefficient of determination of cumulative log returns vs time.

Implements pyfolio’s stability_of_timeseries — fit \(y_t = a + b \cdot t\) to the log-equity curve and return R^2. Closer to 1 means more linear (steady) growth.

Parameters:

returns – Periodic returns (not log).

Returns:

Scalar R^2 expression.

finance_calcs.common_sense_ratio(returns: Expr) Expr[source]

tail_ratio * (1 + cumulative_return) — sanity sniff test.

Parameters:

returns – Periodic returns expression.

Returns:

Scalar expression.

finance_calcs.sharpe_probability(returns: Series, *, benchmark_sharpe: float = 0.0, frequency: Frequency | str | float = Frequency.Day) float[source]

Lopez de Prado probabilistic Sharpe ratio.

Probability that the observed Sharpe is greater than benchmark_sharpe, accounting for sample skew and kurtosis.

Parameters:
  • returns – Periodic returns.

  • benchmark_sharpe – Annualised threshold Sharpe.

  • frequency – Observation frequency alias, enum, or observations per year.

Returns:

Pr(SR_true > benchmark_sharpe) in [0, 1].

finance_calcs.sharpe_deflated_probability(returns: Series, *, trial_count: int, sharpe_variance: float | None = None, frequency: Frequency | str | float = Frequency.Day) float[source]

Deflated Sharpe ratio (Bailey & Lopez de Prado).

Adjusts the probabilistic Sharpe for multiple-testing across trial_count candidate strategies.

Parameters:
  • returns – Periodic returns.

  • trial_count – Number of independent strategies tried.

  • sharpe_variance – Variance of the trial Sharpes. If None a conservative default of 1.0 is used (worst case).

  • frequency – Observation frequency alias, enum, or observations per year.

Returns:

Pr(SR_true > expected_max_SR_under_null) in [0, 1].

finance_calcs.sharpe_minimum_track_record_length(returns: Series, *, benchmark_sharpe: float = 0.0, significance_level: float = 0.05, frequency: Frequency | str | float = Frequency.Day) float[source]

Minimum observations for Sharpe above benchmark at requested confidence.

Parameters:
  • returns – Periodic returns.

  • benchmark_sharpe – Annualised threshold Sharpe.

  • significance_level – Significance level (0.05 → 95% confidence).

  • frequency – Observation frequency alias, enum, or observations per year.

Returns:

Minimum number of observations (float; round up in practice).

finance_calcs.sharpe_bootstrap_confidence_interval(returns: Series, *, bootstrap_samples: int = 1000, confidence_level: float = 0.95, frequency: Frequency | str | float = Frequency.Day, seed: int | None = None) tuple[float, float, float][source]

Bootstrap confidence interval for the Sharpe ratio.

Parameters:
  • returns – Periodic returns.

  • bootstrap_samples – Number of bootstrap resamples.

  • confidence_level – Two-sided confidence level.

  • frequency – Observation frequency alias, enum, or observations per year.

  • seed – RNG seed.

Returns:

Tuple (sharpe, lower, upper).

finance_calcs.sharpe_confidence_interval(returns: Series, *, risk_free: float | Series | ndarray = 0.0, frequency: Frequency | str | float = Frequency.Day, confidence_level: float = 0.95) tuple[float, float, float][source]

Sharpe with a Mertens-style asymptotic confidence interval.

Parameters:
  • returns – Periodic returns.

  • risk_free – Annual risk-free rate (subtracted period-wise) as a scalar, or a per-period rate series (pl.Series / np.ndarray) aligned to returns for a time-varying risk-free rate.

  • frequency – Observation frequency alias, enum, or observations per year.

  • confidence_level – Two-sided confidence level.

Returns:

Tuple (sharpe, lower, upper) where the bounds are derived from the Mertens (2002) asymptotic variance of the Sharpe.


Tail Risk

Tail-risk expression metrics support lifetime, rolling, and period-bucketed calculations. The GPD helpers consume pl.Series and fit a Peaks-over-Threshold model to tail losses.

Function

Use it for

Notes

tail_ratio(returns, *, window=None, period=None, date=None)

Right-tail / left-tail balance

abs(p95) / abs(p05)

ulcer_index(returns, *, window=None, period=None, date=None)

Drawdown depth persistence

Decimal RMS from initial 1.0 equity baseline

omega_ratio(returns, *, required_return=0.0, frequency="daily", window=None, period=None, date=None)

Gain/loss balance around threshold

Scalar hurdle is annual

value_at_risk_generalized_pareto(returns, *, tail_probability=0.01, threshold_probability=0.10)

Extreme VaR from GPD fit

Returns a negative lower-tail return

conditional_value_at_risk_generalized_pareto(returns, *, tail_probability=0.01, threshold_probability=0.10)

Extreme conditional VaR from GPD fit

Returns a negative lower-tail return

finance_calcs.tail_ratio(returns: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Right tail / left tail ratio — |p95| / |p05|.

window=None → scalar; window=N → rolling; period=... → per-bucket.

finance_calcs.ulcer_index(returns: Expr, *, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

RMS of the drawdown sequence, expressed as a decimal.

UI = sqrt(mean(dd_t^2)) where dd_t is the percentage drawdown at time t. window=None → scalar; window=N → rolling RMS over each trailing N-bar window. period=... → per-bucket RMS drawdown. The equity path starts from a 1.0 baseline; multiply the result by 100 for percentage-point units.

finance_calcs.omega_ratio(returns: Expr, *, required_return: float | Expr = 0.0, frequency: Frequency | str | float = Frequency.Day, window: int | None = None, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Omega ratio — gain/loss probability-weighted ratio.

required_return may be a scalar annual threshold or a pl.Expr per-observation column for a time-varying threshold.

finance_calcs.value_at_risk_generalized_pareto(returns: Series, *, tail_probability: float = 0.01, threshold_probability: float = 0.1) float[source]

GPD-fitted extreme VaR as a lower-tail return.

Fits a Generalized Pareto Distribution to the excess of losses over a threshold (peak-over-threshold) and inverts to obtain the tail_probability quantile.

Closed form:

\(VaR_p = u + \frac{\beta}{\xi}\left(\left(\frac{n}{n_u} p\right)^{-\xi} - 1\right)\)

Parameters:
  • returns – Periodic returns (pl.Series).

  • tail_probability – Tail probability (0.01 → 1% VaR).

  • threshold_probability – Probability mass beyond the threshold u used for the GPD fit (0.10 → top-10% of losses).

Returns:

VaR as a negative return.

finance_calcs.conditional_value_at_risk_generalized_pareto(returns: Series, *, tail_probability: float = 0.01, threshold_probability: float = 0.1) float[source]

GPD-fitted extreme CVaR as a lower-tail return.

Closed form for the GPD tail (xi < 1):

\(CVaR_p = \frac{VaR_p}{1 - \xi} + \frac{\beta - \xi u}{1 - \xi}\)

Parameters:
  • returns – Periodic returns.

  • tail_probability – Tail probability.

  • threshold_probability – Mass beyond the threshold used for the fit.

Returns:

CVaR as a negative return.


Market Microstructure

These expression metrics quantify spreads, liquidity, and price impact.

Function

Use it for

quoted_spread_bps(bid, ask, mid=None)

Quoted bid-ask spread in basis points

effective_spread_bps(execution_price, mid_price, side=None)

Execution spread in basis points

realized_spread_bps(execution_price, future_mid_price, side=None)

Post-trade realized spread

order_imbalance(buy_volume, sell_volume)

Normalized buy/sell volume imbalance

amihud_illiquidity(returns, traded_notional)

Absolute return per traded notional

kyle_lambda(returns, signed_volume)

Price impact per signed volume

finance_calcs.quoted_spread_bps(bid: Expr, ask: Expr, *, mid: Expr | None = None) Expr[source]
finance_calcs.effective_spread_bps(execution_price: Expr, mid_price: Expr, *, side: Expr | None = None) Expr[source]
finance_calcs.realized_spread_bps(execution_price: Expr, future_mid_price: Expr, *, side: Expr | None = None) Expr[source]
finance_calcs.order_imbalance(buy_volume: Expr, sell_volume: Expr) Expr[source]
finance_calcs.amihud_illiquidity(returns: Expr, traded_notional: Expr) Expr[source]
finance_calcs.kyle_lambda(returns: Expr, signed_volume: Expr) Expr[source]

Regime and Persistence

Function

Use it for

regime_signal(returns, window=63, threshold=1.0)

Rolling volatility-regime classification

hurst_exponent(values, max_lag=None)

Long-memory and mean-reversion estimate

fractional_difference(values, order, threshold=1e-5)

Memory-preserving fractional differencing

finance_calcs.regime_signal(returns: Expr, *, window: int = 63, threshold: float = 1.0) Expr[source]
finance_calcs.hurst_exponent(values: Series | Sequence[float] | ndarray, *, max_lag: int | None = None) float[source]
finance_calcs.fractional_difference(values: Series | Sequence[float] | ndarray, *, order: float, threshold: float = 1e-05) Series[source]

Portfolio

Portfolio metrics aggregate position weights. They are most useful inside a group_by("date") aggregation over a long-form position panel.

Function

Use it for

Notes

gross_leverage(weights)

Total absolute exposure

Sum of absolute weights

gross_exposure(weights)

Long plus short notional

Alias for gross_leverage

net_exposure(weights)

Signed net exposure

Sum of weights

long_exposure(weights)

Long exposure

Sum of positive weights

short_exposure(weights)

Short exposure

Sum of negative weights, returned as negative

concentration(weights)

Herfindahl concentration

Sum of squared normalized absolute weights

top_n_concentration(weights, n=10)

Top-name exposure share

Gross exposure held by top n absolute weights

active_share(weights, benchmark_weights)

Active share vs benchmark

0.5 * sum(abs(weights - benchmark_weights))

finance_calcs.gross_leverage(weights: Expr) Expr[source]

Sum of absolute weights — total notional / equity.

Parameters:

weights – Position weight expression.

Returns:

Scalar gross-leverage expression.

finance_calcs.gross_exposure(weights: Expr) Expr[source]

Alias for gross_leverage — long + short notional.

Parameters:

weights – Position weight expression.

Returns:

Scalar gross-exposure expression.

finance_calcs.net_exposure(weights: Expr) Expr[source]

Long minus short notional — signed sum of weights.

Parameters:

weights – Position weight expression.

Returns:

Scalar net-exposure expression.

finance_calcs.long_exposure(weights: Expr) Expr[source]

Sum of positive weights.

Parameters:

weights – Position weight expression.

Returns:

Scalar long-exposure expression.

finance_calcs.short_exposure(weights: Expr) Expr[source]

Sum of negative weights (returned as a negative number).

Parameters:

weights – Position weight expression.

Returns:

Scalar short-exposure expression.

finance_calcs.concentration(weights: Expr) Expr[source]

Herfindahl-Hirschman index of normalised absolute weights.

Computed on absolute weights normalised to sum to 1 — yields 1/N for an equal-weight portfolio of N names and 1.0 for a single-name portfolio.

Parameters:

weights – Position weight expression.

Returns:

Scalar HHI expression in (0, 1].

finance_calcs.top_n_concentration(weights: Expr, n: int = 10) Expr[source]

Fraction of gross exposure held by the top n absolute weights.

Parameters:
  • weights – Position weight expression.

  • n – Number of top positions.

Returns:

Scalar expression in [0, 1].

finance_calcs.active_share(weights: Expr, benchmark_weights: Expr) Expr[source]

Active share — 0.5 * sum(|w - b|).

Parameters:
  • weights – Portfolio weight expression.

  • benchmark_weights – Benchmark weight expression aligned to weights.

Returns:

Scalar active-share expression in [0, 1].


Post-Trade

Post-trade utilities consume transaction, round-trip, or execution data. Cost, slippage, turnover, and trade-quality metrics are expression kernels. Round-trip extraction and summary helpers take concrete pl.DataFrame inputs because they need ordered trade sequences.

Function

Use it for

Notes

transaction_notional(quantity, price)

Absolute traded notional

abs(quantity) * price

transaction_cost(quantity, price, *, commission=0.0, fees=0.0, bps=0.0)

Explicit plus basis-point costs

Adds commission, fees, and bps cost on notional

transaction_volume(quantity, price, *, period=None, date=None)

Traded notional volume

Sums notional over the full sample or period bucket

slippage_bps(execution_price, benchmark_price, *, side=None)

Execution slippage

Side-aware when a side expression is provided

implementation_shortfall(execution_price, decision_price, *, side=None)

Decision-price slippage

Side-aware implementation shortfall in bps

vwap_slippage(execution_price, vwap, *, side=None)

VWAP slippage

Side-aware execution vs. VWAP in bps

turnover(weights, *, window=None)

Position-weight turnover

Absolute weight change; optional rolling sum

cost_attribution(transactions)

Cost decomposition

Returns component totals and percentages

extract_round_trips(transactions)

FIFO round-trip extraction

Builds entry/exit trade rows from signed quantities

round_trip_stats(round_trips)

Trade-quality summary

Count, win rate, average PnL, total PnL, PF, payoff

long_short_round_trip_stats(round_trips)

Long/short trade summary

Aggregates round trips by side

sector_round_trip_stats(round_trips, sector_map)

Sector trade summary

Aggregates round trips by mapped sector

win_rate(pnl)

Profitable-trade fraction

Expression metric

profit_factor(pnl)

Gross profit / gross loss

Expression metric

payoff_ratio(pnl)

Average win / average loss

Expression metric

average_trade_pnl(pnl)

Mean trade PnL

Expression metric

trade_duration_stats(duration)

Holding-period summary

Returns mean, median, and max duration

mae_mfe(trades, prices)

Maximum adverse/favorable move

Adds mae and mfe to round trips

consecutive_wins_losses(pnl)

Win/loss streaks

Returns max consecutive wins and losses

exit_reason_stats(trades)

PnL by exit reason

Groups counts and PnL by exit-reason label

trade_size_return_correlation(size, returns)

Size/return relationship

Correlation of absolute trade size with trade return

finance_calcs.transaction_notional(quantity: Expr, price: Expr) Expr[source]

Absolute traded notional, abs(quantity) * price.

finance_calcs.transaction_cost(quantity: Expr, price: Expr, *, commission: float | Expr = 0.0, fees: float | Expr = 0.0, bps: float | Expr = 0.0) Expr[source]

Per-trade cost from explicit charges plus basis-point slippage.

bps is applied to absolute traded notional. commission and fees may be scalars or expressions aligned to the transaction rows.

finance_calcs.transaction_volume(quantity: Expr, price: Expr, *, period: Frequency | str | Expr | None = None, date: Expr | None = None) Expr[source]

Absolute traded notional, summed over the full sample or period.

finance_calcs.slippage_bps(execution_price: Expr, benchmark_price: Expr, *, side: Expr | None = None) Expr[source]

Execution slippage in basis points.

Without side, the result is signed price difference versus the benchmark. With side, positive values mean adverse execution cost for buy/cover and sell/short transactions.

finance_calcs.implementation_shortfall(execution_price: Expr, decision_price: Expr, *, side: Expr | None = None) Expr[source]

Side-aware execution slippage versus the decision price.

finance_calcs.vwap_slippage(execution_price: Expr, vwap: Expr, *, side: Expr | None = None) Expr[source]

Side-aware execution slippage versus VWAP.

finance_calcs.turnover(weights: Expr, *, window: int | None = None) Expr[source]

Portfolio turnover contribution from position-weight changes.

Apply over a symbol/security partition, then aggregate by rebalance date. The contribution is 0.5 * abs(weight - prior_weight).

finance_calcs.cost_attribution(transactions: DataFrame, *, quantity_col: str = 'amount', price_col: str = 'price', commission_col: str = 'commission', fees_col: str = 'fees', bps_col: str = 'bps', spread_bps_col: str = 'spread_bps', market_impact_bps_col: str = 'market_impact_bps', slippage_component: str = 'slippage') DataFrame[source]

Summarize transaction costs by component.

finance_calcs.extract_round_trips(transactions: DataFrame, *, timestamp_col: str = 'timestamp', symbol_col: str = 'symbol', quantity_col: str = 'amount', price_col: str = 'price') DataFrame[source]

Extract FIFO round trips from signed transaction quantities.

finance_calcs.round_trip_stats(round_trips: DataFrame, *, pnl_col: str = 'pnl') dict[str, float | int][source]

Summary statistics for extracted round trips.

finance_calcs.long_short_round_trip_stats(round_trips: DataFrame, *, side_col: str = 'side', pnl_col: str = 'pnl') DataFrame[source]

Round-trip statistics split by long and short trades.

finance_calcs.sector_round_trip_stats(round_trips: DataFrame, sector_map: Mapping[str, str], *, symbol_col: str = 'symbol', pnl_col: str = 'pnl') DataFrame[source]

Round-trip statistics by sector.

finance_calcs.win_rate(pnl: Expr) Expr[source]

Fraction of profitable trades.

finance_calcs.profit_factor(pnl: Expr) Expr[source]

Gross profit divided by absolute gross loss.

finance_calcs.payoff_ratio(pnl: Expr) Expr[source]

Average winning trade divided by absolute average losing trade.

finance_calcs.average_trade_pnl(pnl: Expr) Expr[source]

Mean trade PnL.

finance_calcs.trade_duration_stats(duration: Iterable[Any]) dict[str, float][source]

Mean, median, and maximum holding duration.

finance_calcs.mae_mfe(trades: DataFrame, prices: DataFrame, *, timestamp_col: str = 'timestamp', symbol_col: str = 'symbol', price_col: str = 'price') DataFrame[source]

Attach maximum adverse and favorable excursion to round trips.

finance_calcs.consecutive_wins_losses(pnl: Iterable[Any]) dict[str, int][source]

Maximum consecutive winning and losing trade counts.

finance_calcs.exit_reason_stats(trades: DataFrame, *, reason_col: str = 'exit_reason', pnl_col: str = 'pnl') DataFrame[source]

PnL and counts grouped by exit reason.

finance_calcs.trade_size_return_correlation(size: Expr, returns: Expr) Expr[source]

Correlation between absolute trade size and trade return.