from .market import sanitize_tickers, fetch_price_history, fetch_quotes, infer_sectors from .features import build_features from .models import train_model, build_alpha_signals, top_feature_contributions from .optimizer import optimize_portfolio from .risk import monte_carlo_quantiles, simple_backtest def build_portfolio_payload(tickers, lookback_days, risk_aversion, max_weight, sector_limit, beta_limit): tickers = sanitize_tickers(tickers) if len(tickers) < 2: raise ValueError("Choose at least 2 valid tickers") sector_map = infer_sectors(tickers) raw = fetch_price_history(tickers, lookback_days=lookback_days) feature_df = build_features(raw, sector_map) model, feature_df = train_model(feature_df) latest_df = build_alpha_signals(model, feature_df) weights_df, factor_exposures, aux = optimize_portfolio( latest_predictions=latest_df, feature_df=feature_df, risk_aversion=risk_aversion, max_weight=max_weight, sector_limit=sector_limit, beta_limit=beta_limit, ) quotes = fetch_quotes(tickers) mc = monte_carlo_quantiles(weights_df, feature_df) backtest = simple_backtest(weights_df, feature_df) explain = top_feature_contributions(model, latest_df) metrics = [ {"label": "Expected Return", "value": round(aux["exp_return_daily"] * 252, 4)}, {"label": "Volatility", "value": round(aux["vol_daily"] * (252 ** 0.5), 4)}, { "label": "Sharpe Proxy", "value": round( (aux["exp_return_daily"] * 252) / max(aux["vol_daily"] * (252 ** 0.5), 1e-6), 4, ), }, {"label": "VaR Proxy", "value": round(1 - mc["p05"], 4)}, {"label": "CVaR Proxy", "value": round((1 - mc["p05"]) * 1.15, 4)}, {"label": "Median Terminal", "value": round(mc["p50"], 4)}, ] notes = [ "Live prices come from Yahoo Finance.", "Users choose stocks from buttons, paste text, or upload CSV or TXT.", "Alpha score combines model prediction, momentum, trend, and lower volatility preference.", "Weights now follow cross sectional alpha instead of near equal allocation.", ] return { "tickers": tickers, "weights": weights_df.to_dict(orient="records"), "metrics": metrics, "factor_exposures": factor_exposures, "quotes": quotes, "monte_carlo_quantiles": mc, "backtest_points": backtest, "shap_top_features": explain, "notes": notes, }