Skip to content

API Reference

jquantstats

jQuantStats: Portfolio analytics for quants.

Two entry points

Entry point 1 — prices + positions (recommended for active portfolios):

Use :class:~jquantstats.portfolio.Portfolio when you have price series and position sizes. Portfolio compiles the NAV curve from raw inputs and exposes the full analytics suite via .stats, .plots, and .report.

from jquantstats import Portfolio
import polars as pl

pf = Portfolio.from_cash_position(
    prices=prices_df,
    cash_position=positions_df,
    aum=1_000_000,
)
pf.stats.sharpe()
pf.plots.snapshot()

Entry point 2 — returns series (for arbitrary return streams):

Use :class:~jquantstats.data.Data when you already have a returns series (e.g. downloaded from a data vendor) and want benchmark comparison or factor analytics.

from jquantstats import Data
import polars as pl

data = Data.from_returns(returns=returns_df, benchmark=bench_df)
data.stats.sharpe()
data.plots.snapshot(title="Performance")

The two APIs are layered: portfolio.data returns a :class:~jquantstats.data.Data object so you can always drop into the returns-series API from a Portfolio.

For more information, visit the jQuantStats Documentation <https://jebel-quant.github.io/jquantstats/book>_.

CostModel dataclass

Unified representation of a portfolio transaction-cost model.

Eliminates the implicit "pick one" contract between the two independent cost parameters (cost_per_unit and cost_bps) on :class:~jquantstats.portfolio.Portfolio. A CostModel instance encapsulates one model at a time and can be passed to any Portfolio factory method instead of specifying the raw float parameters.

Attributes:

Name Type Description
cost_per_unit float

One-way cost per unit of position change (Model A). Defaults to 0.0.

cost_bps float

One-way cost in basis points of AUM turnover (Model B). Defaults to 0.0.

Raises:

Type Description
ValueError

If cost_per_unit or cost_bps is negative, or if both are non-zero (which would silently double-count costs).

Examples:

>>> CostModel.per_unit(0.01)
CostModel(cost_per_unit=0.01, cost_bps=0.0)
>>> CostModel.turnover_bps(5.0)
CostModel(cost_per_unit=0.0, cost_bps=5.0)
>>> CostModel.zero()
CostModel(cost_per_unit=0.0, cost_bps=0.0)

per_unit(cost: float) -> CostModel classmethod

Create a Model A (position-delta) cost model.

Parameters:

Name Type Description Default
cost float

One-way cost per unit of position change. Must be non-negative.

required

Returns:

Name Type Description
A CostModel

class:CostModel with cost_per_unit=cost and

CostModel

cost_bps=0.0.

Examples:

>>> CostModel.per_unit(0.01)
CostModel(cost_per_unit=0.01, cost_bps=0.0)

turnover_bps(bps: float) -> CostModel classmethod

Create a Model B (turnover-bps) cost model.

Parameters:

Name Type Description Default
bps float

One-way cost in basis points of AUM turnover. Must be non-negative.

required

Returns:

Name Type Description
A CostModel

class:CostModel with cost_per_unit=0.0 and

CostModel

cost_bps=bps.

Examples:

>>> CostModel.turnover_bps(5.0)
CostModel(cost_per_unit=0.0, cost_bps=5.0)

zero() -> CostModel classmethod

Create a zero-cost model (no transaction costs).

Returns:

Name Type Description
A CostModel

class:CostModel with both parameters set to 0.0.

Examples:

>>> CostModel.zero()
CostModel(cost_per_unit=0.0, cost_bps=0.0)

Data dataclass

A container for financial returns data and an optional benchmark.

This class provides methods for analyzing and manipulating financial returns data, including converting returns to prices, calculating drawdowns, and resampling data to different time periods. It also provides access to statistical metrics through the stats property and visualization through the plots property.

Attributes:

Name Type Description
returns DataFrame

DataFrame containing returns data with assets as columns.

benchmark DataFrame

DataFrame containing benchmark returns data. Defaults to None.

index DataFrame

DataFrame containing the date index for the returns data.

plots: DataPlots property

Provides access to visualization methods for the financial data.

Returns:

Name Type Description
DataPlots DataPlots

An instance of the DataPlots class initialized with this data.

stats: Stats property

Provides access to statistical analysis methods for the financial data.

Returns:

Name Type Description
Stats Stats

An instance of the Stats class initialized with this data.

reports: Reports property

Provides access to reporting methods for the financial data.

Returns:

Name Type Description
Reports Reports

An instance of the Reports class initialized with this data.

utils: DataUtils property

Provides access to utility transforms and conversions for the financial data.

Returns:

Name Type Description
DataUtils DataUtils

An instance of the DataUtils class initialized with this data.

date_col: list[str] property

Return the column names of the index DataFrame.

Returns:

Type Description
list[str]

list[str]: List of column names in the index DataFrame, typically containing the date column name.

assets: list[str] property

Return the combined list of asset column names from returns and benchmark.

Returns:

Type Description
list[str]

list[str]: List of all asset column names from both returns and benchmark (if available).

all: pl.DataFrame property

Combine index, returns, and benchmark data into a single DataFrame.

This property provides a convenient way to access all data in a single DataFrame, which is useful for analysis and visualization.

Returns:

Type Description
DataFrame

pl.DataFrame: A DataFrame containing the index, all returns data, and benchmark data (if available) combined horizontally.

__post_init__() -> None

Validate the Data object after initialization.

from_returns(returns: NativeFrame, rf: NativeFrameOrScalar = 0.0, benchmark: NativeFrame | None = None, date_col: str = 'Date', null_strategy: Literal['raise', 'drop', 'forward_fill'] | None = None) -> Data classmethod

Create a Data object from returns and optional benchmark.

Parameters

returns : NativeFrame Financial returns data. First column should be the date column, remaining columns are asset returns.

float | NativeFrame, optional

Risk-free rate. Default is 0.0 (no risk-free rate adjustment).

  • If float: Constant risk-free rate applied to all dates.
  • If NativeFrame: Time-varying risk-free rate with dates matching returns.
NativeFrame | None, optional

Benchmark returns. Default is None (no benchmark). First column should be the date column, remaining columns are benchmark returns.

str, optional

Name of the date column in the DataFrames. Default is "Date".

{"raise", "drop", "forward_fill"} | None, optional

How to handle null (missing) values in returns and benchmark. Default is None (nulls are left as-is and will propagate through calculations, matching the current Polars behaviour).

  • None — no null checking; nulls propagate through all downstream calculations. This matches Polars' default semantics.
  • "raise" — raise :exc:~jquantstats.exceptions.NullsInReturnsError if any null is found. Use this to be notified of missing data and clean it yourself before construction.
  • "drop" — silently drop every row that contains at least one null. Mirrors the pandas/QuantStats silent-drop behaviour.
  • "forward_fill" — fill each null with the most recent non-null value in the same column.

.. note:: This parameter affects only Polars null values (i.e. None / missing entries). IEEE-754 NaN values (float("nan")) are not nulls in Polars and are not affected — they continue to propagate through calculations as per IEEE-754 semantics.

Returns:

Data Object containing excess returns and benchmark (if any), with methods for analysis and visualization through the stats and plots properties.

Raises:

NullsInReturnsError If null_strategy is "raise" and the data contains null values. ValueError If there are no overlapping dates between returns and benchmark.

Examples:

Basic usage:

from jquantstats import Data
import polars as pl

returns = pl.DataFrame({
    "Date": ["2023-01-01", "2023-01-02", "2023-01-03"],
    "Asset1": [0.01, -0.02, 0.03]
}).with_columns(pl.col("Date").str.to_date())

data = Data.from_returns(returns=returns)

With benchmark and risk-free rate:

benchmark = pl.DataFrame({
    "Date": ["2023-01-01", "2023-01-02", "2023-01-03"],
    "Market": [0.005, -0.01, 0.02]
}).with_columns(pl.col("Date").str.to_date())

data = Data.from_returns(returns=returns, benchmark=benchmark, rf=0.0002)

Handling nulls automatically:

returns_with_nulls = pl.DataFrame({
    "Date": ["2023-01-01", "2023-01-02", "2023-01-03"],
    "Asset1": [0.01, None, 0.03]
}).with_columns(pl.col("Date").str.to_date())

# Drop rows with nulls (mirrors pandas/QuantStats behaviour)
data = Data.from_returns(returns=returns_with_nulls, null_strategy="drop")

# Or forward-fill nulls
data = Data.from_returns(returns=returns_with_nulls, null_strategy="forward_fill")

from_prices(prices: NativeFrame, rf: NativeFrameOrScalar = 0.0, benchmark: NativeFrame | None = None, date_col: str = 'Date', null_strategy: Literal['raise', 'drop', 'forward_fill'] | None = None) -> Data classmethod

Create a Data object from prices and optional benchmark.

Converts price levels to returns via percentage change and delegates to :meth:from_returns. The first row of each asset is dropped because no prior price is available to compute a return.

Parameters

prices : NativeFrame Price-level data. First column should be the date column; remaining columns are asset prices.

float | NativeFrame, optional

Risk-free rate. Forwarded unchanged to :meth:from_returns. Default is 0.0 (no risk-free rate adjustment).

NativeFrame | None, optional

Benchmark prices. Converted to returns in the same way as prices before being forwarded to :meth:from_returns. Default is None (no benchmark).

str, optional

Name of the date column in the DataFrames. Default is "Date".

{"raise", "drop", "forward_fill"} | None, optional

How to handle null (missing) values after converting prices to returns. Forwarded unchanged to :meth:from_returns. Default is None (nulls propagate through calculations).

  • None — no null checking; nulls propagate.
  • "raise" — raise :exc:~jquantstats.exceptions.NullsInReturnsError if any null is found in the derived returns.
  • "drop" — silently drop every row that contains at least one null.
  • "forward_fill" — fill each null with the most recent non-null value.

.. note:: Prices that contain nulls will produce null returns via pct_change(). If you expect missing price entries, pass null_strategy="drop" or null_strategy="forward_fill".

Returns:

Data Object containing excess returns derived from the supplied prices, with methods for analysis and visualization through the stats and plots properties.

Examples:
from jquantstats import Data
import polars as pl

prices = pl.DataFrame({
    "Date": ["2023-01-01", "2023-01-02", "2023-01-03"],
    "Asset1": [100.0, 101.0, 99.0]
}).with_columns(pl.col("Date").str.to_date())

data = Data.from_prices(prices=prices)

__repr__() -> str

Return a string representation of the Data object.

resample(every: str = '1mo') -> Data

Resamples returns and benchmark to a different frequency using Polars.

Parameters:

Name Type Description Default
every str

Resampling frequency (e.g., '1mo', '1y'). Defaults to '1mo'.

'1mo'

Returns:

Name Type Description
Data Data

Resampled data.

describe() -> pl.DataFrame

Return a tidy summary of shape, date range and asset names.

Returns:

pl.DataFrame One row per asset with columns: asset, start, end, rows, has_benchmark.

copy() -> Data

Create a deep copy of the Data object.

Returns:

Name Type Description
Data Data

A new Data object with copies of the returns and benchmark.

head(n: int = 5) -> Data

Return the first n rows of the combined returns and benchmark data.

Parameters:

Name Type Description Default
n int

Number of rows to return. Defaults to 5.

5

Returns:

Name Type Description
Data Data

A new Data object containing the first n rows of the combined data.

tail(n: int = 5) -> Data

Return the last n rows of the combined returns and benchmark data.

Parameters:

Name Type Description Default
n int

Number of rows to return. Defaults to 5.

5

Returns:

Name Type Description
Data Data

A new Data object containing the last n rows of the combined data.

truncate(start: date | datetime | str | int | None = None, end: date | datetime | str | int | None = None) -> Data

Return a new Data object truncated to the inclusive [start, end] range.

When the index is temporal (Date/Datetime), truncation is performed by comparing the date column against start and end values.

When the index is integer-based, row slicing is used instead, and start and end must be non-negative integers. Passing non-integer bounds to an integer-indexed Data raises :exc:TypeError.

Parameters:

Name Type Description Default
start date | datetime | str | int | None

Optional lower bound (inclusive). A date/datetime value when the index is temporal; a non-negative :class:int row index when the data has no temporal index.

None
end date | datetime | str | int | None

Optional upper bound (inclusive). Same type rules as start.

None

Returns:

Name Type Description
Data Data

A new Data object filtered to the specified range.

Raises:

Type Description
TypeError

When the index is not temporal and a non-integer bound is supplied.

items() -> Iterator[tuple[str, pl.Series]]

Iterate over all assets and their corresponding data series.

This method provides a convenient way to iterate over all assets in the data, yielding each asset name and its corresponding data series.

Yields:

Type Description
tuple[str, Series]

tuple[str, pl.Series]: A tuple containing the asset name and its data series.

Portfolio dataclass

Bases: PortfolioNavMixin, PortfolioAttributionMixin, PortfolioTurnoverMixin, PortfolioCostMixin

Portfolio analytics class for quant finance.

Stores the three raw inputs — cash positions, prices, and AUM — and exposes the standard derived data series, analytics facades, transforms, and attribution tools.

Derived data series:

  • :attr:profits — per-asset daily cash P&L
  • :attr:profit — aggregate daily portfolio profit
  • :attr:nav_accumulated — cumulative additive NAV
  • :attr:nav_compounded — compounded NAV
  • :attr:returns — daily returns (profit / AUM)
  • :attr:monthly — monthly compounded returns
  • :attr:highwater — running high-water mark
  • :attr:drawdown — drawdown from high-water mark
  • :attr:all — merged view of all derived series

  • Lazy composition accessors: :attr:stats, :attr:plots, :attr:report

  • Portfolio transforms: :meth:truncate, :meth:lag, :meth:smoothed_holding
  • Attribution: :attr:tilt, :attr:timing, :attr:tilt_timing_decomp
  • Turnover: :attr:turnover, :attr:turnover_weekly, :meth:turnover_summary
  • Cost analysis: :meth:cost_adjusted_returns, :meth:trading_cost_impact
  • Utility: :meth:correlation

Attributes:

Name Type Description
cashposition DataFrame

Polars DataFrame of positions per asset over time (includes date column if present).

prices DataFrame

Polars DataFrame of prices per asset over time (includes date column if present).

aum float

Assets under management used as base NAV offset.

Analytics facades
  • .stats : delegates to the legacy Stats pipeline via .data; all 50+ metrics available.
  • .plots : portfolio-specific Plots; NAV overlays, lead-lag IR, rolling Sharpe/vol, heatmaps.
  • .report : HTML Report; self-contained portfolio performance report.
  • .data : bridge to the legacy Data / Stats / DataPlots pipeline.

.plots and .report are intentionally not delegated to the legacy path: the legacy path operates on a bare returns series, while the analytics path has access to raw prices, positions, and AUM for richer portfolio-specific visualisations.

Cost models

Two independent cost models are provided. They are not interchangeable:

Model A — position-delta (stateful, set at construction): cost_per_unit: float — one-way cost per unit of position change (e.g. 0.01 per share). Used by .position_delta_costs and .net_cost_nav. Best for: equity portfolios where cost scales with shares traded.

Model B — turnover-bps (stateless, passed at call time): cost_bps: float — one-way cost in basis points of AUM turnover (e.g. 5 bps). Used by .cost_adjusted_returns(cost_bps) and .trading_cost_impact(max_bps). Best for: macro / fund-of-funds portfolios where cost scales with notional traded.

To sweep a range of cost assumptions use trading_cost_impact(max_bps=20) (Model B). To compute a net-NAV curve set cost_per_unit at construction and read .net_cost_nav (Model A).

Date column requirement

Most analytics work with or without a date column. The following features require a temporal date column (pl.Date or pl.Datetime):

  • portfolio.plots.correlation_heatmap()
  • portfolio.plots.lead_lag_ir_plot()
  • stats.monthly_win_rate() — returns NaN per column when no date is present
  • stats.annual_breakdown() — raises ValueError when no date is present
  • stats.max_drawdown_duration() — returns period count (int) instead of days

Portfolios without a date column (integer-indexed) are fully supported for NAV, returns, Sharpe, drawdown, cost analytics, and most rolling metrics.

Examples:

>>> import polars as pl
>>> from datetime import date
>>> prices = pl.DataFrame({"date": [date(2020, 1, 1), date(2020, 1, 2)], "A": [100.0, 110.0]})
>>> pos = pl.DataFrame({"date": [date(2020, 1, 1), date(2020, 1, 2)], "A": [1000.0, 1000.0]})
>>> pf = Portfolio(prices=prices, cashposition=pos, aum=1e6)
>>> pf.assets
['A']

cost_model: CostModel property

Return the active cost model as a :class:~jquantstats.CostModel instance.

Returns:

Name Type Description
A CostModel

class:CostModel whose cost_per_unit and cost_bps fields

CostModel

reflect the values stored on this portfolio.

assets: list[str] property

List the asset column names from prices (numeric columns).

Returns:

Type Description
list[str]

list[str]: Names of numeric columns in prices; typically excludes

list[str]

'date'.

data: Data property

Build a legacy :class:~jquantstats._data.Data object from this portfolio's returns.

This bridges the two entry points: Portfolio compiles the NAV curve from prices and positions; the returned :class:~jquantstats._data.Data object gives access to the full legacy analytics pipeline (data.stats, data.plots, data.reports).

Returns:

Type Description
Data

class:~jquantstats._data.Data: A Data object whose returns column

Data

is the portfolio's daily return series and whose index holds the date

Data

column (or a synthetic integer index for date-free portfolios).

Examples:

>>> import polars as pl
>>> from datetime import date
>>> prices = pl.DataFrame({"date": [date(2020, 1, 1), date(2020, 1, 2)], "A": [100.0, 110.0]})
>>> pos = pl.DataFrame({"date": [date(2020, 1, 1), date(2020, 1, 2)], "A": [1000.0, 1000.0]})
>>> pf = Portfolio(prices=prices, cashposition=pos, aum=1e6)
>>> d = pf.data
>>> "returns" in d.returns.columns
True

stats: Stats property

Return a Stats object built from the portfolio's daily returns.

Delegates to the legacy :class:~jquantstats._stats.Stats pipeline via :attr:data, so all analytics (Sharpe, drawdown, summary, etc.) are available through the shared implementation.

The result is cached after first access so repeated calls are O(1).

plots: PortfolioPlots property

Convenience accessor returning a PortfolioPlots facade for this portfolio.

Use this to create Plotly visualizations such as snapshots, lagged performance curves, and lead/lag IR charts.

Returns:

Type Description
PortfolioPlots

class:~jquantstats._plots.PortfolioPlots: Helper object with

PortfolioPlots

plotting methods.

The result is cached after first access so repeated calls are O(1).

report: Report property

Convenience accessor returning a Report facade for this portfolio.

Use this to generate a self-contained HTML performance report containing statistics tables and interactive charts.

Returns:

Type Description
Report

class:~jquantstats._reports.Report: Helper object with

Report

report methods.

The result is cached after first access so repeated calls are O(1).

utils: PortfolioUtils property

Convenience accessor returning a PortfolioUtils facade for this portfolio.

Use this for common data transformations such as converting returns to prices, computing log returns, rebasing, aggregating by period, and computing exponential standard deviation.

Returns:

Type Description
PortfolioUtils

class:~jquantstats._utils.PortfolioUtils: Helper object with

PortfolioUtils

utility transform methods.

The result is cached after first access so repeated calls are O(1).

__post_init__() -> None

Validate input types, shapes, and parameters post-initialization.

__repr__() -> str

Return a string representation of the Portfolio object.

describe() -> pl.DataFrame

Return a tidy summary of shape, date range and asset names.

Returns:

pl.DataFrame One row per asset with columns: asset, start, end, rows.

Examples:

>>> import polars as pl
>>> from datetime import date
>>> prices = pl.DataFrame({"date": [date(2020, 1, 1), date(2020, 1, 2)], "A": [100.0, 110.0]})
>>> pos = pl.DataFrame({"date": [date(2020, 1, 1), date(2020, 1, 2)], "A": [1000.0, 1000.0]})
>>> pf = Portfolio(prices=prices, cashposition=pos, aum=1e6)
>>> df = pf.describe()
>>> list(df.columns)
['asset', 'start', 'end', 'rows']

from_risk_position(prices: pl.DataFrame, risk_position: pl.DataFrame, aum: float, vola: int | dict[str, int] = 32, vol_cap: float | None = None, cost_per_unit: float = 0.0, cost_bps: float = 0.0, cost_model: CostModel | None = None) -> Self classmethod

Create a Portfolio from per-asset risk positions.

De-volatizes each risk position using an EWMA volatility estimate derived from the corresponding price series.

Parameters:

Name Type Description Default
prices DataFrame

Price levels per asset over time (may include a date column).

required
risk_position DataFrame

Risk units per asset aligned with prices.

required
vola int | dict[str, int]

EWMA lookback (span-equivalent) used to estimate volatility. Pass an int to apply the same span to every asset, or a dict[str, int] to set a per-asset span (assets absent from the dict default to 32). Every span value must be a positive integer; a ValueError is raised otherwise. Dict keys that do not correspond to any numeric column in prices also raise a ValueError.

32
vol_cap float | None

Optional lower bound for the EWMA volatility estimate. When provided, the vol series is clipped from below at this value before dividing the risk position, preventing position blow-up in calm, low-volatility regimes. For example, vol_cap=0.05 ensures annualised vol is never estimated below 5%. Must be positive when not None.

None
aum float

Assets under management used as the base NAV offset.

required
cost_per_unit float

One-way trading cost per unit of position change. Defaults to 0.0 (no cost). Ignored when cost_model is given.

0.0
cost_bps float

One-way trading cost in basis points of AUM turnover. Defaults to 0.0 (no cost). Ignored when cost_model is given.

0.0
cost_model CostModel | None

Optional :class:~jquantstats.CostModel instance. When supplied, its cost_per_unit and cost_bps values take precedence over the individual parameters above.

None

Returns:

Type Description
Self

A Portfolio instance whose cash positions are risk_position

Self

divided by EWMA volatility.

Raises:

Type Description
ValueError

If any span value in vola is ≤ 0, or if a key in a vola dict does not match any numeric column in prices, or if vol_cap is provided but is not positive.

from_position(prices: pl.DataFrame, position: pl.DataFrame, aum: float, cost_per_unit: float = 0.0, cost_bps: float = 0.0, cost_model: CostModel | None = None) -> Self classmethod

Create a Portfolio from share/unit positions.

Converts position (number of units held per asset) to cash exposure by multiplying element-wise with prices, then delegates to :py:meth:from_cash_position.

Parameters:

Name Type Description Default
prices DataFrame

Price levels per asset over time (may include a date column).

required
position DataFrame

Number of units held per asset over time, aligned with prices. Non-numeric columns (e.g. 'date') are passed through unchanged.

required
aum float

Assets under management used as the base NAV offset.

required
cost_per_unit float

One-way trading cost per unit of position change. Defaults to 0.0 (no cost). Ignored when cost_model is given.

0.0
cost_bps float

One-way trading cost in basis points of AUM turnover. Defaults to 0.0 (no cost). Ignored when cost_model is given.

0.0
cost_model CostModel | None

Optional :class:~jquantstats.CostModel instance. When supplied, its cost_per_unit and cost_bps values take precedence over the individual parameters above.

None

Returns:

Type Description
Self

A Portfolio instance whose cash positions equal position x prices.

Examples:

>>> import polars as pl
>>> prices = pl.DataFrame({"A": [100.0, 110.0, 105.0]})
>>> pos = pl.DataFrame({"A": [10.0, 10.0, 10.0]})
>>> pf = Portfolio.from_position(prices=prices, position=pos, aum=1e6)
>>> pf.cashposition["A"].to_list()
[1000.0, 1100.0, 1050.0]

from_cash_position(prices: pl.DataFrame, cash_position: pl.DataFrame, aum: float, cost_per_unit: float = 0.0, cost_bps: float = 0.0, cost_model: CostModel | None = None) -> Self classmethod

Create a Portfolio directly from cash positions aligned with prices.

Parameters:

Name Type Description Default
prices DataFrame

Price levels per asset over time (may include a date column).

required
cash_position DataFrame

Cash exposure per asset over time.

required
aum float

Assets under management used as the base NAV offset.

required
cost_per_unit float

One-way trading cost per unit of position change. Defaults to 0.0 (no cost). Ignored when cost_model is given.

0.0
cost_bps float

One-way trading cost in basis points of AUM turnover. Defaults to 0.0 (no cost). Ignored when cost_model is given.

0.0
cost_model CostModel | None

Optional :class:~jquantstats.CostModel instance. When supplied, its cost_per_unit and cost_bps values take precedence over the individual parameters above.

None

Returns:

Type Description
Self

A Portfolio instance with the provided cash positions.

truncate(start: date | datetime | str | int | None = None, end: date | datetime | str | int | None = None) -> Portfolio

Return a new Portfolio truncated to the inclusive [start, end] range.

When a 'date' column is present in both prices and cash positions, truncation is performed by comparing the 'date' column against start and end (which should be date/datetime values or strings parseable by Polars).

When the 'date' column is absent, integer-based row slicing is used instead. In this case start and end must be non-negative integers representing 0-based row indices. Passing non-integer bounds to an integer-indexed portfolio raises :exc:TypeError.

In all cases the aum value is preserved.

Parameters:

Name Type Description Default
start date | datetime | str | int | None

Optional lower bound (inclusive). A date/datetime or Polars-parseable string when a 'date' column exists; a non-negative int row index when the data has no 'date' column.

None
end date | datetime | str | int | None

Optional upper bound (inclusive). Same type rules as start.

None

Returns:

Type Description
Portfolio

A new Portfolio instance with prices and cash positions filtered

Portfolio

to the specified range.

Raises:

Type Description
TypeError

When the portfolio has no 'date' column and a non-integer bound is supplied.

lag(n: int) -> Portfolio

Return a new Portfolio with cash positions lagged by n steps.

This method shifts the numeric asset columns in the cashposition DataFrame by n rows, preserving the 'date' column and any non-numeric columns unchanged. Positive n delays weights (moves them down); negative n leads them (moves them up); n == 0 returns the current portfolio unchanged.

Notes

Missing values introduced by the shift are left as nulls; downstream profit computation already guards and treats nulls as zero when multiplying by returns.

Parameters:

Name Type Description Default
n int

Number of rows to shift (can be negative, zero, or positive).

required

Returns:

Type Description
Portfolio

A new Portfolio instance with lagged cash positions and the same

Portfolio

prices/AUM as the original.

smoothed_holding(n: int) -> Portfolio

Return a new Portfolio with cash positions smoothed by a rolling mean.

Applies a trailing window average over the last n steps for each numeric asset column (excluding 'date'). The window length is n + 1 so that:

  • n=0 returns the original weights (no smoothing),
  • n=1 averages the current and previous weights,
  • n=k averages the current and last k weights.

Parameters:

Name Type Description Default
n int

Non-negative integer specifying how many previous steps to include.

required

Returns:

Type Description
Portfolio

A new Portfolio with smoothed cash positions and the same

Portfolio

prices/AUM.

correlation(frame: pl.DataFrame, name: str = 'portfolio') -> pl.DataFrame

Compute a correlation matrix of asset returns plus the portfolio.

Computes percentage changes for all numeric columns in frame, appends the portfolio profit series under the provided name, and returns the Pearson correlation matrix across all numeric columns.

Parameters:

Name Type Description Default
frame DataFrame

A Polars DataFrame containing at least the asset price columns (and a date column which will be ignored if non-numeric).

required
name str

The column name to use when adding the portfolio profit series to the input frame.

'portfolio'

Returns:

Type Description
DataFrame

A square Polars DataFrame where each cell is the correlation

DataFrame

between a pair of series (values in [-1, 1]).