# Portfolio Outlook: real-data methods (v0.2.0)

This is a standalone portfolio forecasting laboratory, separate from Style Rotation. Enter 1–8 USD stocks/ETFs, allocations, a 1/6/12-month horizon, a starting value, a rebalancing rule and turnover costs. The authenticated website fetches actual histories, refits models, evaluates earlier forecasts, and simulates 2,000 possible future portfolio paths. No synthetic fallback is permitted. A default portfolio is an example allocation, not a recommendation.

## Data and timing

* Yahoo Finance daily **split/dividend-adjusted closes** produce monthly simple return proxies. This is not a separately audited total-return index. Only complete calendar months are used; no silent forward filling, gap deletion or conversion of missing returns to zero. Every input holding and factor must have common uninterrupted history of at least 120 months. Supported assets are USD equities/ETFs with valid vendor histories. Prices currently come from the public Yahoo chart endpoint; availability/rate limits are not guaranteed.
* SPY, IWM and IWD provide broad-market, small-cap and value ETF exposures. They are correlated traded factors, not pure Fama–French factors. Asset regressions include an intercept. If a holding is itself a factor, its factor mapping is exact rather than estimated.
* The Philadelphia Fed Real-Time Data Set supplies employment, CPI and unemployment **historical vintage** workbooks. Employment and CPI become year-over-year growth within the same vintage; unemployment is a level. Each formation date selects only a vintage whose month ended at least one full month earlier. The extra buffer is conservative; it is not an assertion of exact release timestamps. Unemployment is a quarterly-vintage series and may have an older reference date. Dates and full vintage audit are included in each download. Macro vintage age above 125 days or observation age above 185 days fails closed.
* New snapshots use the last complete month; cache life is 6 hours for market downloads and 24 hours for macro workbooks/snapshots. Missing data fails visibly. Raw response hashes, retrieval dates, transformed-input hash and source-code hash accompany each run.
* Current vendor prices may incorporate later corrections. Historical macro vintages mitigate revision leakage but do not make the whole study fully point-in-time. Present-day tickers introduce survivorship and selection bias. No delisting database is included.

## Forecast construction

The fixed candidate pool contains a raw joint stationary block bootstrap, a historical-mean model with filtered risk, a ridge-regularized joint factor/macro autoregression, and a nonlinear random-Fourier-feature ridge model. Scaling, regressions and residual filters are fitted separately at each origin with at most 120 months of past data (60-month minimum). Hyperparameters are fixed in source; no neural foundation model, regime-switching model or full Bayesian posterior is claimed to be implemented.

For the three model-based candidates, variance-targeted **GJR-GARCH** supplies asymmetric conditional volatility. Parameters are selected from a fixed stationary grid using Gaussian quasi-likelihood, not unrestricted maximum likelihood. Innovations need not be Gaussian: standardized historical factor/macro/asset residuals are sampled jointly in stationary blocks with expected length 3 months. The implementation includes 10% correlation shrinkage. This preserves much observed dependence and tail behavior but cannot create a full spectrum of unprecedented crises or parameter uncertainty. Volatility estimates from monthly data and short rolling windows are noisy.

The ensemble adapts to **same-horizon portfolio CRPS**, rather than picking the best in-sample asset model. At each test date only earlier forecasts whose full horizon has elapsed are eligible. The last 36 matured origins receive exponentially decaying weights (half-life 12 origins). Relative CRPS losses feed a softmax of fixed intensity 3, shrunk 50% toward equal weights; fewer than 12 matured observations implies equal weights. One model is sampled for each entire trajectory to retain coherent path dependence. SPY benchmark paths share the same trajectory draws.

Portfolio accounting tracks holdings, weights and one-way turnover. Monthly rebalancing pays the specified cost; buy-and-hold permits weights to drift. There are no initial/terminal trading costs, cash flows, taxes, leverage, short positions or exact defaults. Drawdowns are month-end drawdowns, which miss intramonth losses.

An optional macro scenario moves the latest available states linearly to user-specified terminal changes. A Gaussian linear conditional-innovation projection imposes the path on model-based simulations. The unconditional raw bootstrap has no macro-conditioning mechanism and is excluded from scenario mixtures. Remaining ensemble weights are renormalized. A scenario is a conditional association, not a causal estimate or forecast of its occurrence; scenario-specific forecast skill has not been validated.

## Evaluation

Each request evaluates the requested portfolio at quarterly origins, up to 84 most recent origins with matured outcomes, refitting all candidates at each date. The same portfolio weights, horizon, costs and rebalance rule apply to realized and simulated results. Candidate distributions use 300 paths per origin; current forecasts use 2,000. Reported statistics include CRPS, 80% interval coverage, interval score, loss-event Brier score, and PIT (the latter two detail fields also appear in the JSON).

Adaptive weights and interval adjustments use only matured earlier outcomes. The empirical 80% interval correction uses normalized earlier interval violations. Report adjusted coverage separately from raw coverage. This is **not** a claim of exact conformal coverage under dependent, nonstationary returns; it does not calibrate loss or outperformance probabilities.

Paired circular-block resampling of ensemble-minus-bootstrap CRPS differences uses 2,000 bootstrap draws and block sizes 4 and 8 quarterly origins. These intervals are exploratory, account only approximately for dependence, and are not corrected for repeated model/portfolio searches. No untouched prospective holdout has yet been collected. The site retains the benchmark and displays an unfavorable result rather than claiming sophistication establishes skill.

## Primary references

* [Yahoo: adjusted close definitions](https://help.yahoo.com/kb/SLN28256.html).
* [Philadelphia Fed: real-time full histories and vintages](https://www.philadelphiafed.org/surveys-and-data/real-time-data-research/real-time-data-set-full-time-series-history).
* [ARCH documentation: volatility forecasting and filtered residual bootstrap](https://arch.readthedocs.io/en/latest/univariate/forecasting.html).
* [ARCH documentation: forecasting under scenarios](https://arch.readthedocs.io/en/latest/univariate/univariate_volatility_scenarios.html).
* The broader [research review](RESEARCH.md) discusses additional contemporary methods and original papers. Inclusion in that review does not imply implementation. Transformer/foundation-model adapters need separate licensing, compute, rolling-origin evaluation and evidence before inclusion.

## Reproduction and deployment

Install this Python project, then run `python -m portfolio_forecast.service --holdings SPY=.4,AAPL=.2,MSFT=.2,JPM=.2 --horizon 12 --output outputs/historical/live-12.json`. Run `python -m unittest discover -s tests -v` for the accounting, timing, risk and authentication tests. Historical provider revisions can change a later reproduction; retain each JSON's hashes and vintage audit.

The website's Python endpoint verifies the same approved-member Supabase policy as the existing JavaScript APIs. Legacy-password mode is used only when account auth is unconfigured. Requests carry credentials via the HttpOnly session cookie or in-memory header, never a new URL parameter. Responses are not CDN cached. Website Python dependencies are pinned; deployment requires a Python 3.12 Vercel runtime. Export with `python website/scripts/export-live-portfolio.py` from the parent checkout after editing the standalone package. The older demo exporter is retired.
