Analysis

class Alpha

Bases: object

Calculates Jensen’s alpha of portfolio returns relative to a benchmark.

Alpha measures the excess return of a portfolio over the return predicted by its beta exposure to the benchmark (CAPM). The per-period alpha is:

alpha = (mean_portfolio - rf) - beta * (mean_benchmark - rf)

where beta is the sample (ddof = 1) beta of the portfolio against the benchmark. The per-period alpha is then annualized geometrically over period (default 252):

alpha_annual = (1 + alpha)^period - 1

The risk-free rate rf is specified per period (default 0.0).

# References

  • Jensen, M. C. (1968). “The Performance of Mutual Funds in the Period 1945-1964”. Journal of Finance, 23(2), 389-416.

  • CFA Institute Investment Foundations, 3rd Edition

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
calculate_from_returns_with_benchmark(returns, benchmark)
name
class AvgLoser

Bases: object

Calculates the average losing trade from realized PnLs.

Only negative PnLs count as losers. Returns NaN for an empty series or when there are no losing trades.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(_returns)
name
class AvgWinner

Bases: object

Calculates the average winning trade from realized PnLs.

Only positive PnLs count as winners. Returns NaN for an empty series or when there are no winning trades.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(_returns)
name
class BetaRatio

Bases: object

Calculates the beta of portfolio returns relative to a benchmark.

Beta measures the systematic risk (market sensitivity) of a portfolio and is calculated as the covariance of the portfolio and benchmark returns divided by the variance of the benchmark returns:

Beta = Cov(portfolio, benchmark) / Var(benchmark)

Sample (Bessel-corrected, ddof = 1) covariance and variance are used to match the standard deviation convention elsewhere in this crate. Beta is not annualized.

# References

  • Sharpe, W. F. (1964). “Capital Asset Prices: A Theory of Market Equilibrium under Conditions of Risk”. Journal of Finance, 19(3), 425-442.

  • CFA Institute Investment Foundations, 3rd Edition

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
calculate_from_returns_with_benchmark(returns, benchmark)
name
class CAGR

Bases: object

Calculates the Compound Annual Growth Rate (CAGR) for returns.

CAGR represents the mean annual growth rate of an investment over a specified period, assuming the profits were reinvested at the end of each period.

Formula: CAGR = (Ending Value / Beginning Value)^(Period/Days) - 1

For returns: CAGR = ((1 + Total Return)^(Period/Days)) - 1

# References

  • Bacon, C. R. (2008). Practical Portfolio Performance Measurement and Attribution (2nd ed.). Wiley.

  • CFA Institute Level I Curriculum: Quantitative Methods

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class CalmarRatio

Bases: object

Calculates the Calmar Ratio for returns.

The Calmar Ratio is a function of the fund’s average compounded annual rate of return versus its maximum drawdown. The higher the Calmar ratio, the better it performed on a risk-adjusted basis during the given time frame.

Formula: Calmar Ratio = CAGR / |Max Drawdown|

# References

  • Young, T. W. (1991). “Calmar Ratio: A Smoother Tool”. Futures, 20(1).

  • Bacon, C. R. (2008). Practical Portfolio Performance Measurement and Attribution (2nd ed.). Wiley.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class DownCaptureRatio

Bases: object

Calculates the down capture ratio of portfolio returns relative to a benchmark.

The down capture ratio measures how the portfolio performed, on average, during the periods when the benchmark return was negative. It is the ratio of the portfolio’s geometric annualized return to the benchmark’s geometric annualized return, both computed over the down-market subset only:

DownCapture = annualized_return(portfolio | benchmark < 0) / annualized_return(benchmark | benchmark < 0)

where each side’s annualized return is the geometric (CAGR-style) value (prod(1 + x_i))^(period / m) - 1 and m is the number of down-market periods (the size of the filtered subset, not the full aligned length). The period defaults to 252 trading days. A value below 1.0 means the portfolio lost less than the benchmark in down markets (smaller drawdowns), which is desirable.

This is the empyrical.down_capture convention (geometric annualized-return ratio over the benchmark < 0 subset). Note that this differs from the Morningstar definition, which uses a ratio of cumulative (non-annualized) returns; the two coincide only when both subsets contain the same number of periods.

# References

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
calculate_from_returns_with_benchmark(returns, benchmark)
name
class Expectancy

Bases: object

Calculates the expectancy of a trading strategy based on realized PnLs.

Expectancy is defined as: (Average Win × Win Rate) + (Average Loss × Loss Rate) This metric provides insight into the expected profitability per trade and helps evaluate the overall edge of a trading strategy.

A positive expectancy indicates a profitable system over time, while a negative expectancy suggests losses.

# References

  • Tharp, V. K. (1998). Trade Your Way to Financial Freedom. McGraw-Hill.

  • Elder, A. (1993). Trading for a Living. John Wiley & Sons.

  • Vince, R. (1992). The Mathematics of Money Management. John Wiley & Sons.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(_returns)
name
class ExpectedShortfall

Bases: object

Calculates the historical Expected Shortfall (Conditional Value at Risk) of portfolio returns.

Expected Shortfall is the average of the losses that occur beyond the [ValueAtRisk](crate::statistics::value_at_risk::ValueAtRisk) threshold at a given confidence level - the mean of the worst 1 - confidence tail of the return distribution. It is a coherent risk measure and captures tail severity that VaR alone does not.

ES(c) = mean( r | r <= VaR(c) )

confidence defaults to 0.95. The result is expressed as a return (e.g. -0.05 is a 5% expected tail loss); it is always less than or equal to the corresponding VaR. Returns NaN for an empty series.

# References

  • Acerbi, C., & Tasche, D. (2002). “Expected Shortfall: A Natural Coherent Alternative to Value at Risk”. Economic Notes, 31(2), 379-388.

  • Rockafellar, R. T., & Uryasev, S. (2000). “Optimization of Conditional Value-at-Risk”. Journal of Risk, 2(3), 21-41.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class InformationRatio

Bases: object

Calculates the information ratio of portfolio returns relative to a benchmark.

The information ratio measures active return per unit of active risk (tracking error):

IR = mean(active) / std(active) * sqrt(period)

where active_i = portfolio_i - benchmark_i, std uses Bessel’s correction (ddof = 1), and the ratio is annualized by the square root of the specified period (default: 252 trading days).

# References

  • Goodwin, T. H. (1998). “The Information Ratio”. Financial Analysts Journal, 54(4), 34-43.

  • CFA Institute Investment Foundations, 3rd Edition

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
calculate_from_returns_with_benchmark(returns, benchmark)
name
class LongRatio

Bases: object

Calculates the ratio of long positions to total positions.

A position counts as long when its entry (opening order) side is Buy. The result is in [0, 1], rounded to precision decimal places, and is None for an empty position list.

calculate_from_positions(positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
name
class MaxDrawdown

Bases: object

Calculates the Maximum Drawdown for returns.

Maximum Drawdown is the maximum observed loss from a peak to a trough, before a new peak is attained. It is an indicator of downside risk over a specified time period.

Formula: Max((Peak - Trough) / Peak) for all peak-trough sequences

The equity curve compounds returns from a starting value of 1.0, and the result is reported as a negative fraction (e.g. -0.20 is a 20% drawdown).

# References

  • Bacon, C. R. (2008). Practical Portfolio Performance Measurement and Attribution (2nd ed.). Wiley.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class MaxLoser

Bases: object

Calculates the largest losing trade (most negative PnL) from realized PnLs.

Only negative PnLs count as losers. Returns NaN for an empty series or when there are no losing trades.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(_returns)
name
class MaxWinner

Bases: object

Calculates the largest winning trade from realized PnLs.

Only positive PnLs count as winners. Returns NaN for an empty series or when there are no winning trades.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(returns)
name
class MinLoser

Bases: object

Calculates the smallest losing trade (least negative PnL) from realized PnLs.

Only negative PnLs count as losers. Returns NaN for an empty series or when there are no losing trades.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(_returns)
name
class MinWinner

Bases: object

Calculates the smallest winning trade from realized PnLs.

Only positive PnLs count as winners. Returns NaN for an empty series or when there are no winning trades.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(_returns)
name
class OmegaRatio

Bases: object

Calculates the Omega ratio of portfolio returns.

The Omega ratio is the ratio of probability-weighted gains to losses relative to a return threshold θ. It captures the entire return distribution (all moments), unlike the Sharpe ratio which only uses the first two:

Omega(θ) = sum(max(r - θ, 0)) / sum(max(θ - r, 0))

The threshold θ defaults to 0 (gains vs losses about zero). A value above 1 means gains above the threshold outweigh losses below it. Returns NaN for an empty series, or when there are no returns below the threshold (the ratio is undefined).

# References

  • Keating, C., & Shadwick, W. F. (2002). “A Universal Performance Measure”. Journal of Performance Measurement, 6(3), 59-84.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class PortfolioAnalyzer

Bases: object

Analyzes portfolio performance and calculates various statistics.

The PortfolioAnalyzer tracks account balances, positions, and realized PnLs to provide portfolio analysis including returns, PnL calculations, and customizable statistics.

add_position_return(timestamp, value)

Records a position return at a specific timestamp.

add_positions(positions)

Adds new positions for analysis.

add_return(timestamp, value)

Records a return at a specific timestamp.

This is a backward-compatible alias for Self.add_position_return.

add_trade(position_id, ts_event, realized_pnl)

Records a trade’s PnL realized at ts_event.

currencies()

Returns all tracked currencies.

deregister_statistic(statistic)

Removes a specific statistic from calculation.

deregister_statistics()

Removes all registered statistics.

get_performance_stats_general()

Gets general portfolio statistics.

get_performance_stats_pnls(currency, unrealized_pnl)

Gets all PnL-related performance statistics.

# Errors

Returns an error if PnL calculations fail, for example due to:

  • No currency specified for a multi-currency portfolio.

  • Unrealized PnL currency not matching the specified currency.

  • Specified currency not found in account balances.

get_performance_stats_portfolio_returns()

Gets all portfolio-return-based performance statistics.

get_performance_stats_position_returns()

Gets all position-return-based performance statistics.

get_performance_stats_returns()

Gets all return-based performance statistics.

get_performance_stats_returns_vs_benchmark(benchmark)

Gets all benchmark-relative return statistics for the primary returns.

This is stateless: the benchmark series is supplied by the caller rather than stored on the analyzer. Only statistics that override PortfolioStatistic.calculate_from_returns_with_benchmark (the benchmark-relative statistics) contribute values; all others return None and are skipped.

get_stats_general_formatted()

Gets formatted general statistics as strings.

get_stats_pnls_formatted(currency, unrealized_pnl)

Gets formatted PnL statistics as strings.

# Errors

Returns an error if PnL statistics calculation fails.

get_stats_portfolio_returns_formatted()

Gets formatted portfolio-return statistics as strings.

get_stats_position_returns_formatted()

Gets formatted position-return statistics as strings.

get_stats_returns_formatted()

Gets formatted return statistics as strings.

portfolio_returns()

Returns the portfolio calculated returns.

position_returns()

Returns the per-position calculated returns.

realized_pnls(currency)

Retrieves realized PnLs for a specific currency.

Each record is (position_id, ts_event, realized_pnl). Returns None if no PnLs exist, or if multiple currencies exist without an explicit currency specified.

record_trade(position_id, ts_event, realized_pnl)

Records a trade’s PnL realized at ts_event, observed during portfolio processing.

register_statistic(statistic)

Registers a new portfolio statistic for calculation.

reset()

Resets all analysis data to initial state.

returns()

Returns the primary calculated returns.

This returns portfolio returns when available, otherwise it falls back to position returns for backward compatibility.

statistic(name)

Retrieves a specific statistic by name.

total_pnl(currency, unrealized_pnl)

Calculates total PnL including unrealized PnL if provided.

# Errors

Returns an error if: - No currency is specified in a multi-currency portfolio. - The specified currency is not found in account balances. - The unrealized PnL currency does not match the specified currency.

total_pnl_percentage(currency, unrealized_pnl)

Calculates total PnL as a percentage of starting balance.

# Errors

Returns an error if: - No currency is specified in a multi-currency portfolio. - The specified currency is not found in account balances. - The unrealized PnL currency does not match the specified currency.

class PortfolioStatistics

Bases: object

An owned snapshot of computed portfolio performance statistics.

pnls is keyed by currency code, each value mapping statistic name to value.

general
pnls
returns
returns_series
class ProfitFactor

Bases: object

Calculates the profit factor based on portfolio returns.

Profit factor is defined as the ratio of gross profits to gross losses: Sum(Positive Returns) / Abs(Sum(Negative Returns))

A profit factor greater than 1.0 indicates a profitable strategy, while a factor less than 1.0 indicates losses exceed gains.

Generally: - 1.0-1.5: Modest profitability - 1.5-2.0: Good profitability - > 2.0: Excellent profitability

# References

  • Tharp, V. K. (1998). Trade Your Way to Financial Freedom. McGraw-Hill.

  • Kaufman, P. J. (2013). Trading Systems and Methods (5th ed.). Wiley.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class ReturnsAverage

Bases: object

Calculates the arithmetic mean of portfolio returns.

All returns are included, so zero returns count toward the average. Returns NaN for an empty series.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class ReturnsAverageLoss

Bases: object

Calculates the arithmetic mean of the negative portfolio returns.

Zero returns are excluded (neither wins nor losses). Returns NaN for an empty series or when there are no negative returns.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class ReturnsAverageWin

Bases: object

Calculates the arithmetic mean of the positive portfolio returns.

Zero returns are excluded (neither wins nor losses). Returns NaN for an empty series or when there are no positive returns.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class ReturnsKurtosis

Bases: object

Calculates the excess kurtosis of portfolio returns.

Kurtosis measures the heaviness of the tails of the return distribution relative to a normal distribution. A positive value indicates fatter tails (more outliers); a negative value indicates thinner tails.

Uses the bias-corrected sample excess kurtosis (adjusted Fisher-Pearson), matching pandas.Series.kurt and Excel KURT. A normal distribution yields 0:

`G2 = n(n + 1) / ((n - 1)(n - 2)(n - 3)) * sum(((x - mean) / s)^4)
  • 3(n - 1)^2 / ((n - 2)(n - 3))`

where s is the sample standard deviation (Bessel’s correction, ddof=1). Returns NaN for fewer than four returns or zero dispersion.

# References

  • Joanes, D. N., & Gill, C. A. (1998). Comparing measures of sample skewness and kurtosis. Journal of the Royal Statistical Society: Series D, 47(1), 183-189.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class ReturnsSkewness

Bases: object

Calculates the skewness of portfolio returns.

Skewness measures the asymmetry of the return distribution about its mean. A negative value indicates a longer left tail (downside outliers); a positive value indicates a longer right tail.

Uses the bias-corrected sample skewness (adjusted Fisher-Pearson), matching pandas.Series.skew and Excel SKEW:

G1 = n / ((n - 1)(n - 2)) * sum(((x - mean) / s)^3)

where s is the sample standard deviation (Bessel’s correction, ddof=1). Returns NaN for fewer than three returns or zero dispersion.

# References

  • Joanes, D. N., & Gill, C. A. (1998). Comparing measures of sample skewness and kurtosis. Journal of the Royal Statistical Society: Series D, 47(1), 183-189.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class ReturnsVolatility

Bases: object

Calculates the annualized volatility (standard deviation) of portfolio returns.

Volatility is calculated as the standard deviation of returns, annualized by multiplying the daily standard deviation by the square root of the period: Standard Deviation * sqrt(period)

Uses Bessel’s correction (ddof=1) for sample standard deviation. This provides a measure of the portfolio’s risk or uncertainty of returns.

# References

  • CFA Institute Level I Curriculum: Quantitative Methods

  • Hull, J. C. (2018). Options, Futures, and Other Derivatives (10th ed.). Pearson.

  • Fabozzi, F. J., et al. (2002). The Handbook of Financial Instruments. Wiley.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class RiskReturnRatio

Bases: object

Calculates the risk-return ratio (mean/std) for portfolio returns.

This is a non-annualized ratio of mean return to standard deviation. For an annualized version, use SharpeRatio.

Downsamples high-frequency returns to daily bins before calculation for consistency with other ratio-based statistics.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class SharpeRatio

Bases: object

Calculates the Sharpe ratio for portfolio returns.

The Sharpe ratio measures risk-adjusted return and is calculated as: (Mean Return - Risk-free Rate) / Standard Deviation of Returns * sqrt(period)

This implementation assumes a risk-free rate of 0 and annualizes the ratio using the square root of the specified period (default: 252 trading days).

# References

  • Sharpe, W. F. (1966). “Mutual Fund Performance”. Journal of Business, 39(1), 119-138.

  • Sharpe, W. F. (1994). “The Sharpe Ratio”. Journal of Portfolio Management, 21(1), 49-58.

  • CFA Institute Investment Foundations, 3rd Edition

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class SortinoRatio

Bases: object

Calculates the Sortino ratio for portfolio returns.

The Sortino ratio is a variation of the Sharpe ratio that only penalizes downside volatility, making it more appropriate for strategies with asymmetric return distributions.

Formula: Mean Return / Downside Deviation * sqrt(period)

Where downside deviation is calculated as: sqrt(sum(negative_returns^2) / total_observations)

Note: Uses total observations count (not just negative returns) as per Sortino’s methodology.

# References

  • Sortino, F. A., & van der Meer, R. (1991). “Downside Risk”. Journal of Portfolio Management, 17(4), 27-31.

  • Sortino, F. A., & Price, L. N. (1994). “Performance Measurement in a Downside Risk Framework”. Journal of Investing, 3(3), 59-64.

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class TailRatio

Bases: object

Calculates the tail ratio of portfolio returns.

The tail ratio compares the magnitude of the right (gain) tail to the left (loss) tail of the return distribution. It is the absolute ratio of the 95th to the 5th percentile of returns:

TailRatio = | percentile(r, 95) / percentile(r, 5) |

Percentiles use linear interpolation between closest ranks, matching numpy.percentile and pandas.Series.quantile with the default linear method (the convention used by the quantstats tail-ratio definition).

A value greater than 1 indicates a heavier upside tail (gains larger in magnitude than losses); a value below 1 indicates a heavier downside tail. Returns NaN for fewer than two returns or when the 5th percentile is zero.

# References

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class TrackingError

Bases: object

Calculates the tracking error of portfolio returns relative to a benchmark.

Tracking error is the volatility of the active return (portfolio minus benchmark):

TE = std(active) * sqrt(period)

where active_i = portfolio_i - benchmark_i, std uses Bessel’s correction (ddof = 1), and the result is annualized by the square root of the specified period (default: 252 trading days).

# References

  • Roll, R. (1992). “A Mean/Variance Analysis of Tracking Error”. Journal of Portfolio Management, 18(4), 13-22.

  • CFA Institute Investment Foundations, 3rd Edition

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
calculate_from_returns_with_benchmark(returns, benchmark)
name
class TreynorRatio

Bases: object

Calculates the Treynor ratio of portfolio returns relative to a benchmark.

The Treynor ratio measures excess return per unit of systematic risk (beta):

Treynor = (annualized_return - rf_annual) / beta

The portfolio’s annualized return is computed geometrically (CAGR-style) from the aligned returns: annualized_return = (prod(1 + r_i))^(period / n) - 1. The per-period risk-free rate is annualized geometrically as rf_annual = (1 + rf)^period - 1. Beta is the sample (ddof = 1) beta of the portfolio against the benchmark. The period defaults to 252 trading days and rf defaults to 0.0.

# References

  • Treynor, J. L. (1965). “How to Rate Management of Investment Funds”. Harvard Business Review, 43(1), 63-75.

  • CFA Institute Investment Foundations, 3rd Edition

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
calculate_from_returns_with_benchmark(returns, benchmark)
name
class UlcerIndex

Bases: object

Calculates the Ulcer Index of portfolio returns.

The Ulcer Index measures downside risk as the root-mean-square of the percentage drawdowns of the cumulative-return equity curve. Unlike volatility it only penalizes downside deviations, and unlike maximum drawdown it accounts for both the depth and the duration of drawdowns.

The equity curve compounds returns from a starting value of 1.0, and each drawdown is measured against the running peak (matching the convention used by [MaxDrawdown](super::max_drawdown::MaxDrawdown)):

UI = sqrt( mean( D_i^2 ) ), where D_i = (peak_i - equity_i) / peak_i

Drawdowns are expressed as fractions (0.05 = 5%), so the result is on the same scale as MaxDrawdown (the original definition uses percentage points). Returns 0.0 for an empty series.

# References

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class UpCaptureRatio

Bases: object

Calculates the up capture ratio of portfolio returns relative to a benchmark.

The up capture ratio measures how the portfolio performed, on average, during the periods when the benchmark return was positive. It is the ratio of the portfolio’s geometric annualized return to the benchmark’s geometric annualized return, both computed over the up-market subset only:

UpCapture = annualized_return(portfolio | benchmark > 0) / annualized_return(benchmark | benchmark > 0)

where each side’s annualized return is the geometric (CAGR-style) value (prod(1 + x_i))^(period / m) - 1 and m is the number of up-market periods (the size of the filtered subset, not the full aligned length). The period defaults to 252 trading days. A value above 1.0 means the portfolio outperformed the benchmark in up markets.

This is the empyrical.up_capture convention (geometric annualized-return ratio over the benchmark > 0 subset). Note that this differs from the Morningstar definition, which uses a ratio of cumulative (non-annualized) returns; the two coincide only when both subsets contain the same number of periods.

# References

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(_returns)
calculate_from_returns_with_benchmark(returns, benchmark)
name
class ValueAtRisk

Bases: object

Calculates the historical Value at Risk (VaR) of portfolio returns.

VaR is the loss threshold that returns are not expected to exceed at a given confidence level. This is the non-parametric (historical) estimator: the empirical quantile of the return distribution at 1 - confidence.

VaR(c) = quantile(returns, 1 - c)

The quantile uses linear interpolation between closest ranks (matching numpy.percentile). confidence defaults to 0.95. The result is expressed as a return (e.g. -0.03 is a 3% loss threshold); more negative means greater risk. Returns NaN for an empty series.

# References

  • Jorion, P. (2007). Value at Risk: The New Benchmark for Managing Financial Risk (3rd ed.). McGraw-Hill.

  • J.P. Morgan/Reuters (1996). RiskMetrics Technical Document (4th ed.).

calculate_from_positions(_positions)
calculate_from_realized_pnls(_realized_pnls)
calculate_from_returns(raw_returns)
name
class WinRate

Bases: object

Calculates the win rate of a trading strategy based on realized PnLs.

Win rate is the percentage of profitable trades out of total trades: Count(Trades with PnL > 0) / Total Trades

Returns a value between 0.0 and 1.0, where 1.0 represents 100% winning trades.

Note: While a high win rate is desirable, it should be considered alongside average win/loss sizes and profit factor for complete system evaluation.

# References

  • Standard trading performance metric across the industry

  • Tharp, V. K. (1998). Trade Your Way to Financial Freedom. McGraw-Hill.

  • Kaufman, P. J. (2013). Trading Systems and Methods (5th ed.). Wiley.

calculate_from_positions(_positions)
calculate_from_realized_pnls(realized_pnls)
calculate_from_returns(_returns)
name

Configuration for tearsheet generation and visualization.

class TearsheetChart

Bases: object

Base class for tearsheet chart configuration.

Concrete chart classes define which chart to render (via name) and can expose additional arguments (via kwargs) that are passed into the chart renderer.

title: str | None = None
property name: str
kwargs() dict[str, Any]
class TearsheetRunInfoChart

Bases: TearsheetChart

TearsheetRunInfoChart(*, title: ‘str | None’ = None)

property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetStatsTableChart

Bases: TearsheetChart

TearsheetStatsTableChart(*, title: ‘str | None’ = None)

property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetEquityChart

Bases: TearsheetChart

TearsheetEquityChart(*, title: ‘str | None’ = None)

property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetDrawdownChart

Bases: TearsheetChart

TearsheetDrawdownChart(*, title: ‘str | None’ = None)

property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetMonthlyReturnsChart

Bases: TearsheetChart

TearsheetMonthlyReturnsChart(*, title: ‘str | None’ = None, compounding: ‘bool’ = True)

compounding: bool = True
property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetDistributionChart

Bases: TearsheetChart

TearsheetDistributionChart(*, title: ‘str | None’ = None)

property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetRollingSharpeChart

Bases: TearsheetChart

TearsheetRollingSharpeChart(*, title: ‘str | None’ = None)

property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetYearlyReturnsChart

Bases: TearsheetChart

TearsheetYearlyReturnsChart(*, title: ‘str | None’ = None, compounding: ‘bool’ = True)

compounding: bool = True
property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetBarsWithFillsChart

Bases: TearsheetChart

Render bars_with_fills for a specific bar type (string form accepted).

bar_type: str
property name: str
kwargs() dict[str, Any]
title: str | None = None
class TearsheetCustomChart

Bases: TearsheetChart

Configure a tearsheet chart by its registered name.

This is intended for charts registered for tearsheet integration (i.e. present in the tearsheet chart spec registry).

chart: str
args: dict[str, Any]
property name: str
kwargs() dict[str, Any]
title: str | None = None
class GridLayout

Bases: object

Grid layout specification for tearsheet subplots.

Parameters:
  • rows (int, default 4) – Number of rows in the grid.

  • cols (int, default 2) – Number of columns in the grid.

  • heights (list[float], default [0.50, 0.22, 0.16, 0.12]) – Relative heights for each row (must sum to 1.0 or be proportional).

  • vertical_spacing (float, default 0.10) – Vertical spacing between subplots (0.0 to 1.0).

  • horizontal_spacing (float, default 0.10) – Horizontal spacing between subplots (0.0 to 1.0).

rows: int = 4
cols: int = 2
heights: list[float]
vertical_spacing: float = 0.1
horizontal_spacing: float = 0.1
class TearsheetConfig

Bases: object

Configuration for tearsheet generation.

Parameters:
  • charts (list[TearsheetChart], default built-ins) – Charts to include in the tearsheet, in order. Example: charts=[TearsheetRunInfoChart(title=”Run Info”)].

  • theme (str, default "plotly_white") – Theme name for visualization styling. Built-in themes: “plotly_white”, “plotly_dark”, “nautilus”, “nautilus_dark”.

  • layout (GridLayout | None, default None) – Custom grid layout specification. If None, auto-calculated based on charts.

  • title (str, default "NautilusTrader Backtest Results") – Title for the tearsheet.

  • include_benchmark (bool, default True) – Whether to include benchmark comparison in visualizations. Only applies when benchmark_returns data is provided.

  • benchmark_name (str, default "Benchmark") – Display name for the benchmark in visualizations.

  • height (int, default 1500) – Total height of the tearsheet in pixels.

  • show_logo (bool, default True) – Whether to display NautilusTrader logo in the tearsheet.

charts: list[TearsheetChart]
theme: str = 'plotly_white'
layout: GridLayout | None = None
title: str = 'NautilusTrader Backtest Results'
include_benchmark: bool = True
benchmark_name: str = 'Benchmark'
height: int = 1500
property chart_names: list[str]

Backtest visualization and tearsheet generation using Plotly.

This module provides functions to create interactive tearsheets and plots from backtest results, using backtest result statistics and report DataFrames.

register_chart(name: str, func: Callable | None = None) Callable | None

Register a custom chart function for standalone use.

Registered charts are retrievable via get_chart and list_charts. Placing a custom chart in a tearsheet grid uses the separate register_tearsheet_chart path (see the visualization guide); a name registered here is not rendered by TearsheetCustomChart.

Can be used as a decorator or called directly.

Parameters:
  • name (str) – The chart name for later lookup via get_chart / list_charts.

  • func (Callable, optional) – Chart function that returns a plotly Figure. Should accept (returns: pd.Series, **kwargs) as parameters. If None, returns a decorator.

Returns:

The decorated function if used as a decorator, otherwise None.

Return type:

Callable or None

Raises:

ValueError – If name is empty or func is not callable.

Examples

>>> # As a decorator
>>> @register_chart("my_custom_chart")
... def create_custom_chart(returns: pd.Series, **kwargs) -> go.Figure:
...     fig = go.Figure()
...     # ... custom visualization logic
...     return fig
>>>
>>> # Or called directly
>>> register_chart("another_chart", create_custom_chart)
get_chart(name: str) Callable

Get registered chart function by name.

Parameters:

name (str) – The chart name.

Returns:

The chart function.

Return type:

Callable

Raises:

KeyError – If the chart name is not registered.

list_charts() list[str]

List all registered chart names.

Returns:

List of available chart names.

Return type:

list[str]

create_tearsheet(engine: BacktestEngine | BacktestResult, output_path: str | None = 'tearsheet.html', title: str = 'NautilusTrader Backtest Results', currency=None, config=None, benchmark_returns: pd.Series | None = None, benchmark_name: str = 'Benchmark', node: BacktestNode | None = None, run_config_id: str | None = None) str | None

Generate an interactive HTML tearsheet from backtest results.

Parameters:
  • engine (BacktestEngine or BacktestResult) – The completed backtest engine or result.

  • output_path (str, optional) – Path to save the tearsheet. File extension selects the format: .html (interactive), or .png, .jpg, .webp, .svg, .pdf (static, via Kaleido). If None, returns HTML string.

  • title (str, default "NautilusTrader Backtest Results") – Title for the tearsheet.

  • currency (Currency, optional) – Currency filter for PnL statistics, account balances, and engine-derived returns. For BacktestResult input, the stored return series remains unchanged. If None, includes all available currencies.

  • config (TearsheetConfig, optional) – Configuration for tearsheet customization. If None, uses default configuration.

  • benchmark_returns (pd.Series, optional) – Benchmark returns series for comparison. If provided, benchmark will be overlaid on visualizations.

  • benchmark_name (str, default "Benchmark") – Display name for the benchmark.

  • node (BacktestNode, optional) – The node which produced a BacktestResult. Provide it for starting balances or charts that read cached data, such as bars_with_fills. The matching run configuration must set dispose_on_completion=False.

  • run_config_id (str, optional) – The run configuration ID. Defaults to engine.run_config_id.

Returns:

HTML string if output_path is None, otherwise None.

Return type:

str or None

Raises:
  • ImportError – If plotly is not installed.

  • ValueError – If bars_with_fills is configured without a node, a supplied node has no run configuration ID, or the matching run configuration sets dispose_on_completion=True.

create_tearsheet_from_stats(stats_pnls: dict[str, Any] | dict[str, dict[str, Any]], stats_returns: dict[str, Any], stats_general: dict[str, Any], returns: Series, output_path: str | None = 'tearsheet.html', title: str = 'NautilusTrader Backtest Results', config=None, benchmark_returns: Series | None = None, benchmark_name: str = 'Benchmark', run_info: dict[str, Any] | None = None, account_info: dict[str, Any] | None = None, engine=None) str | None

Generate an interactive HTML tearsheet from precomputed statistics.

This lower-level API is useful for offline analysis when you have precomputed statistics and don’t want to pass an engine.

Parameters:
  • stats_pnls (dict[str, Any]) – PnL-based statistics.

  • stats_returns (dict[str, Any]) – Returns-based statistics.

  • stats_general (dict[str, Any]) – General statistics.

  • returns (pd.Series) – Returns series.

  • output_path (str, optional) – Path to save the tearsheet. File extension selects the format: .html (interactive), or .png, .jpg, .webp, .svg, .pdf (static, via Kaleido). If None, returns HTML string.

  • title (str, default "NautilusTrader Backtest Results") – Title for the tearsheet.

  • config (TearsheetConfig, optional) – Configuration for tearsheet customization. If None, uses default configuration.

  • benchmark_returns (pd.Series, optional) – Benchmark returns series for comparison. If provided, benchmark will be overlaid on visualizations.

  • benchmark_name (str, default "Benchmark") – Display name for the benchmark.

  • run_info (dict[str, Any], optional) – Run metadata (run ID, timestamps, backtest period, event counts).

  • account_info (dict[str, Any], optional) – Account information (starting/ending balances per currency).

  • engine (BacktestEngine, optional) – The backtest engine. Required for charts that need engine access (e.g., bars_with_fills).

Returns:

HTML string if output_path is None, otherwise None.

Return type:

str or None

Raises:

ImportError – If plotly is not installed.

Examples

>>> # Offline analysis with precomputed stats
>>> stats_returns = {"Sharpe Ratio (252 days)": 1.5}
>>> stats_general = {"Win Rate": 0.55}
>>> stats_pnls = {"PnL (total)": 10000.0}
>>> returns = pd.Series([0.01, -0.02])
>>> html = create_tearsheet_from_stats(
...     stats_pnls,
...     stats_returns,
...     stats_general,
...     returns,
...     output_path=None,  # Return HTML instead of saving
... )
create_equity_curve(returns: Series, output_path: str | None = None, title: str = 'Equity Curve', benchmark_returns: Series | None = None, benchmark_name: str = 'Benchmark') Figure

Create an interactive equity curve plot with optional benchmark overlay.

Parameters:
  • returns (pd.Series) – Returns series.

  • output_path (str, optional) – Path to save HTML plot. If None, plot is not saved.

  • title (str, default "Equity Curve") – Plot title.

  • benchmark_returns (pd.Series, optional) – Benchmark returns series for comparison. If provided, benchmark equity curve will be overlaid on the chart.

  • benchmark_name (str, default "Benchmark") – Display name for the benchmark in the legend.

Returns:

Plotly figure object.

Return type:

go.Figure

Raises:

ImportError – If plotly is not installed.

create_drawdown_chart(returns: Series, output_path: str | None = None, title: str = 'Drawdown', theme: str = 'plotly_white') Figure

Create an interactive drawdown chart.

Parameters:
  • returns (pd.Series) – Returns series.

  • output_path (str, optional) – Path to save HTML plot. If None, plot is not saved.

  • title (str, default "Drawdown") – Plot title.

  • theme (str, default "plotly_white") – Theme name for styling.

Returns:

Plotly figure object.

Return type:

go.Figure

Raises:

ImportError – If plotly is not installed.

create_monthly_returns_heatmap(returns: Series, output_path: str | None = None, title: str | None = None, compounding: bool = True) Figure

Create an interactive monthly returns heatmap.

Parameters:
  • returns (pd.Series) – Returns series.

  • output_path (str, optional) – Path to save HTML plot. If None, plot is not saved.

  • title (str, optional) – Plot title. Defaults to a basis-aware title derived from compounding.

  • compounding (bool, default True) – If True, cells compound against the running start-of-month balance. If False, cells are simple returns on fixed initial capital that sum to the total return (the nominal rate of return).

Returns:

Plotly figure object.

Return type:

go.Figure

Raises:

ImportError – If plotly is not installed.

create_returns_distribution(returns: Series, output_path: str | None = None, title: str = 'Returns Distribution') Figure

Create an interactive returns distribution histogram.

Parameters:
  • returns (pd.Series) – Returns series.

  • output_path (str, optional) – Path to save HTML plot. If None, plot is not saved.

  • title (str, default "Returns Distribution") – Plot title.

Returns:

Plotly figure object.

Return type:

go.Figure

Raises:

ImportError – If plotly is not installed.

create_rolling_sharpe(returns: Series, window: int = 60, output_path: str | None = None, title: str = 'Rolling Sharpe Ratio (60-day)') Figure

Create an interactive rolling Sharpe ratio chart.

Parameters:
  • returns (pd.Series) – Returns series.

  • window (int, default 60) – Rolling window size in days.

  • output_path (str, optional) – Path to save HTML plot. If None, plot is not saved.

  • title (str, default "Rolling Sharpe Ratio (60-day)") – Plot title.

Returns:

Plotly figure object.

Return type:

go.Figure

Raises:

ImportError – If plotly is not installed.

create_yearly_returns(returns: Series, output_path: str | None = None, title: str | None = None, compounding: bool = True) Figure

Create an interactive yearly returns bar chart.

Parameters:
  • returns (pd.Series) – Returns series.

  • output_path (str, optional) – Path to save HTML plot. If None, plot is not saved.

  • title (str, optional) – Plot title. Defaults to a basis-aware title derived from compounding.

  • compounding (bool, default True) – If True, bars compound against the running start-of-year balance. If False, bars are simple returns on fixed initial capital that sum to the total return (the nominal rate of return).

Returns:

Plotly figure object.

Return type:

go.Figure

Raises:

ImportError – If plotly is not installed.

create_bars_with_fills(engine: BacktestEngine, bar_type: BarType, title: str | None = None, theme: str = 'plotly_white', output_path: str | None = None) go.Figure

Create a candlestick chart with order fills overlaid as bar charts.

This visualization shows price bars (OHLC) as candlesticks and order fills as vertical bars colored by side (buy/sell).

Parameters:
  • engine – The backtest engine with completed run.

  • bar_type (BarType) – The bar type to visualize.

  • title (str, optional) – Plot title. If None, uses bar_type string.

  • theme (str, default "plotly_white") – Theme name for styling.

  • output_path (str, optional) – Path to save HTML plot. If None, plot is not saved.

Returns:

Plotly figure object with candlestick and fill bars.

Return type:

go.Figure

Raises:

ImportError – If plotly is not installed.

register_tearsheet_chart(name: str, subplot_type: str, title: str, renderer: Callable) None

Register a custom chart renderer for tearsheet integration.

The registered name can then be placed in a tearsheet via TearsheetConfig(charts=[TearsheetCustomChart(chart=name)]). This differs from register_chart, which registers standalone chart functions that return their own figure; tearsheet renderers instead draw onto a shared subplot grid cell.

Parameters:
  • name (str) – Chart name referenced by TearsheetCustomChart(chart=name).

  • subplot_type (str) – Plotly subplot type (‘scatter’, ‘bar’, ‘table’, ‘heatmap’, ‘histogram’).

  • title (str) – Display title for the subplot.

  • renderer (Callable) – Function that adds traces to the figure. Signature: renderer(fig, row, col, returns, stats_pnls, stats_returns, stats_general, theme_config, benchmark_returns, benchmark_name, run_info, account_info, engine, **kwargs)

Raises:

ValueError – If name is empty or renderer is not callable.

Theme registry and built-in themes for tearsheet visualization.

get_theme(name: str) dict[str, Any]

Get theme configuration by name.

Parameters:

name (str) – The theme name. Built-in themes: “plotly_white”, “plotly_dark”, “nautilus”, “nautilus_dark”.

Returns:

Theme configuration dictionary with “template” and “colors” keys.

Return type:

dict[str, Any]

Raises:

KeyError – If the theme name is not registered.

register_theme(name: str, template: str, colors: dict[str, str]) None

Register a custom theme.

Parameters:
  • name (str) – The theme name for future reference.

  • template (str) – Plotly template name (e.g., “plotly_white”, “plotly_dark”, “ggplot2”).

  • colors (dict[str, str]) – Color palette dictionary. Expected keys: “primary”, “positive”, “negative”, “neutral”, “background”, “grid”. All values should be hex color codes.

Raises:

ValueError – If name is empty or colors dict is missing required keys.

Examples

>>> register_theme(
...     "custom",
...     "plotly_white",
...     {
...         "primary": "#ff6600",
...         "positive": "#00ff00",
...         "negative": "#ff0000",
...         "neutral": "#808080",
...         "background": "#ffffff",
...         "grid": "#dddddd",
...     },
... )
list_themes() list[str]

List all registered theme names.

Returns:

List of available theme names.

Return type:

list[str]

Pandas report generation for backtest results.

pandas is an optional dependency (pip install pandas); it is imported lazily so that nautilus_trader.analysis can be imported without it.

class ReportProvider

Bases: object

Provides various portfolio analysis reports.

static generate_orders_report(orders: list) pd.DataFrame
static generate_order_fills_report(orders: list) pd.DataFrame
static generate_fills_report(orders: list) pd.DataFrame
static generate_positions_report(positions: list, snapshots: list | None = None) pd.DataFrame
static generate_account_report(account) pd.DataFrame