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.