Skip to content

Size a portfolio from forecasts

Use @forecast when each instrument produces a numeric signal but the whole portfolio should be sized together. Choose this shape instead of on_tick() orders or book(). A forecast returns a scalar; it does not submit trades.

Start with a predictable portfolio

"""Deterministic forecast sizing example; replace fixed volatility for research."""
from atom.library.forecast import forecast, forecast_sizing

universe = ["TCS", "INFY"]
sizing = forecast_sizing(vol_target=0.05, idm=1.0)


def vol(symbol):
    return 0.20


@forecast
def signal():
    return 10.0

This learning example deliberately uses fixed 20% annualized volatility and a constant positive forecast. It is not an investment signal. Supply real, aligned volatility estimates before evaluating an actual trading idea.

A forecast of 10 is average positive strength. Its weight is (10 / 10) * (0.05 / 0.20) * 1.0 = 0.25, so each instrument desires 25% of portfolio equity and the two together desire 50% gross exposure. At equity 100,000 and prices 100, that requests 250 units each before costs, constraints and execution. The next available opening prices determine confirmed fills.

Choose the inputs and defaults

forecast_sizing defaults to forecast_cap=20, vol_target=0.20, idm="auto" and idm_cap=2.5. Forecasts are clipped to plus/minus the cap. Negative values request short exposure, zero requests zero weight, and None omits that member from the new desired portfolio; it does not mean keep its previous target.

The vol(symbol) input is annualized volatility as a fraction: 0.20 means 20%, not 0.20%. It must cover each forecast instrument with a usable positive estimate. Missing volatility prevents sizing. A forecast of 20 with default volatility target and a 20% volatility estimate requests twice the equity before diversification and constraints: forecasts are not percentages.

With idm="auto", a supplied cov(weights) function returns annualized portfolio variance for the weighted book. The diversification multiplier is the sum of absolute weighted instrument volatilities divided by portfolio volatility, capped by idm_cap. Missing covariance or effectively zero portfolio variance falls back to multiplier 1. A numeric idm, as in the example, uses that value directly. Apply suitable portfolio constraints; sizing does not guarantee affordable fills or a realized volatility outcome.

Keep signal calculation separate from actions

Price/indicator reads belong inside the forecast function, with enough history for the chosen calculation. Each instrument has its own bound data context. Calling order helpers inside the function raises ForecastOrderError.

Forecasts are collected and sized on dispatched observations; a declared universe does not create missing data. Use an aligned panel for joint sizing. The current forecast path does not call manage(). Continuous manage() is supported with book(), where it runs before a due book recomputation, including between recomputations. Do not add a manage() function to a forecast strategy and assume it protects its positions.

See target portfolios for the book alternative and risk checks for entry gating. Forecast errors and rejected orders must be inspected alongside positions when checking a backtest.