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
backtestonce per AUM level, each time with the cost modelcost_factorybuilds 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) insidecost_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 tobacktestasreturns_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 toCostModel.- periodint
Annualization factor forwarded to
summary.
- Returns:
- dict of str to numpy.ndarray
aum,net_sharpe,net_annual_returnandtotal_cost, one entry per AUM level, aligned withaums.
- Raises:
- ValueError
If
aumsis not 1-D, orweightsandXdo 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