capacity_curveΒΆ

Defined in fynance.backtest

capacity_curve(weights, X, aums, cost_factory, period=252)[source]

Sweep net performance across a book of AUM levels.

Runs backtest once per AUM level, each time with the cost model cost_factory builds for that level. The caller encodes how cost should scale with size (e.g. a market-impact coefficient growing with the square root of AUM) inside cost_factory; this function only orchestrates the sweep and collects the results.

Parameters:
weightsarray-like

Position/weight book, shape (T,) for a single asset or (T, N) for a multi-asset book.

Xarray-like

Price levels aligned with weights (same shape); passed to backtest as returns_input=False.

aumsarray-like

1-D array of AUM levels to sweep, typically increasing.

cost_factorycallable

Maps an AUM level (float) to a cost model (e.g. MarketImpactCost) conforming to CostModel.

periodint

Annualization factor forwarded to summary.

Returns:
dict of str to numpy.ndarray

aum, net_sharpe, net_annual_return and total_cost, one entry per AUM level, aligned with aums.

Raises:
ValueError

If aums is not 1-D, or weights and X do not share the same shape.

Examples

A single-asset strategy with a small planted edge (0.06% of the signal per bar) and turnover from a noisy signal, swept across AUM levels with a square-root market-impact factory: net Sharpe degrades monotonically as impact grows with size.

>>> import numpy as np
>>> from fynance.backtest.cost import MarketImpactCost
>>> rng = np.random.default_rng(0)
>>> steps = np.cumsum(rng.normal(0.0, 0.07, size=300))
>>> weights = np.clip(steps, -1.0, 1.0)
>>> noise = rng.normal(0.0, 0.01, size=300)
>>> returns = np.empty(300)
>>> returns[0] = noise[0]
>>> returns[1:] = 0.0006 * weights[:-1] + noise[1:]
>>> prices = 100.0 * np.cumprod(1.0 + returns)
>>> aums = np.array([1e5, 1e7, 1e9])
>>> cost_factory = lambda aum: MarketImpactCost(
...     impact=0.0017 * np.sqrt(aum / 1e6), exponent=1.5
... )
>>> out = capacity_curve(weights, prices, aums, cost_factory)
>>> sorted(out)
['aum', 'net_annual_return', 'net_sharpe', 'total_cost']
>>> bool(np.all(np.diff(out['net_sharpe']) <= 1e-9))
True