diff --git a/pages/ETF_Portfolio_Builder.py b/pages/ETF_Portfolio_Builder.py
index 747edee..6f3b5f0 100644
--- a/pages/ETF_Portfolio_Builder.py
+++ b/pages/ETF_Portfolio_Builder.py
@@ -1659,45 +1659,28 @@ def remove_ticker(ticker_to_remove: str) -> None:
# Display current tickers in the main space
if st.session_state.etf_allocations:
st.subheader("Selected ETFs")
- st.markdown("""
-
- """, unsafe_allow_html=True)
- # Create a container for tickers
- ticker_container = st.container()
- with ticker_container:
- # Display each ticker with a close button
- for etf in st.session_state.etf_allocations:
- col1, col2 = st.columns([0.05, 0.95]) # Adjusted column ratio
- with col1:
+ # Create four columns for the tables with smaller widths
+ col1, col2, col3, col4 = st.columns([1, 1, 1, 1])
+
+ # Split the ETFs into four groups
+ etf_groups = [[] for _ in range(4)]
+ for i, etf in enumerate(st.session_state.etf_allocations):
+ group_index = i % 4
+ etf_groups[group_index].append(etf)
+
+ # Display each group in its own column
+ for i, (col, etf_group) in enumerate(zip([col1, col2, col3, col4], etf_groups)):
+ with col:
+ for etf in etf_group:
+ st.markdown(f"""
+
+ {etf['ticker']}
+
+ """, unsafe_allow_html=True)
if st.button("×", key=f"remove_{etf['ticker']}",
help=f"Remove {etf['ticker']} from portfolio"):
remove_ticker(etf['ticker'])
- with col2:
- st.markdown(f"{etf['ticker']}
", unsafe_allow_html=True)
# Debug information
logger.info("=== Session State Debug ===")
@@ -1829,7 +1812,15 @@ with st.sidebar:
# Create a container for ETF input
with st.container():
- # Input field for ETF ticker only
+ # Input field for ETF ticker with improved visibility
+ st.markdown("""
+
+ """, unsafe_allow_html=True)
new_ticker = st.text_input("ETF Ticker", help="Enter a valid ETF ticker (e.g., SCHD)")
# Add button to add ETF
@@ -2872,55 +2863,221 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
investment_horizon=investment_horizon
)
- # Get AI suggestions
+ # Get AI suggestions for different strategies
with st.spinner("Analyzing ETFs and generating portfolio suggestions..."):
try:
- portfolio = selection_service.select_etfs(goal)
+ # Strategy 1: Balanced Growth
+ balanced_goal = InvestmentGoal(
+ capital_target=capital_target,
+ income_target=income_target if income_target > 0 else None,
+ risk_tolerance=RiskTolerance.MODERATE,
+ investment_horizon=investment_horizon
+ )
+ balanced_portfolio = selection_service.select_etfs(balanced_goal)
+
+ # Strategy 2: Income Focus
+ income_goal = InvestmentGoal(
+ capital_target=capital_target,
+ income_target=income_target * 1.2 if income_target > 0 else capital_target * 0.05, # 20% higher income target
+ risk_tolerance=RiskTolerance.CONSERVATIVE,
+ investment_horizon=investment_horizon
+ )
+ income_portfolio = selection_service.select_etfs(income_goal)
+
+ # Strategy 3: Growth Focus
+ growth_goal = InvestmentGoal(
+ capital_target=capital_target,
+ income_target=income_target * 0.8 if income_target > 0 else None, # 20% lower income target
+ risk_tolerance=RiskTolerance.AGGRESSIVE,
+ investment_horizon=investment_horizon
+ )
+ growth_portfolio = selection_service.select_etfs(growth_goal)
+
+ # Strategy 4: Risk-Adjusted
+ risk_adjusted_goal = InvestmentGoal(
+ capital_target=capital_target,
+ income_target=income_target if income_target > 0 else None,
+ risk_tolerance=RiskTolerance[risk_tolerance.upper()],
+ investment_horizon=investment_horizon
+ )
+ risk_adjusted_portfolio = selection_service.select_etfs(risk_adjusted_goal)
+
+ # Create tabs for each strategy
+ strategy_tabs = st.tabs([
+ "🔄 Balanced Growth",
+ "💰 Income Focus",
+ "📈 Growth Focus",
+ "⚖️ Risk-Adjusted"
+ ])
+
+ # Display Balanced Growth Strategy
+ with strategy_tabs[0]:
+ st.write("### Balanced Growth Strategy")
+ st.write("A balanced approach focusing on both growth and income, suitable for most investors.")
+ if balanced_portfolio:
+ portfolio_df = pd.DataFrame(balanced_portfolio)
+ portfolio_df['Allocation (%)'] = portfolio_df['allocation'] * 100
+ portfolio_df['Amount ($)'] = portfolio_df['amount']
+
+ st.dataframe(
+ portfolio_df[['ticker', 'name', 'Allocation (%)', 'Amount ($)']],
+ hide_index=True
+ )
+
+ # Display metrics
+ metrics_df = pd.DataFrame([
+ {
+ 'Ticker': etf['ticker'],
+ 'Expense Ratio (%)': etf['metrics']['expense_ratio'] * 100,
+ 'AUM ($B)': etf['metrics']['aum'] / 1e9,
+ 'Volatility (%)': etf['metrics']['volatility'] * 100,
+ 'Max Drawdown (%)': etf['metrics']['max_drawdown'] * 100,
+ 'Sharpe Ratio': etf['metrics']['sharpe_ratio'],
+ 'Dividend Yield (%)': etf['metrics']['dividend_yield'] * 100
+ }
+ for etf in balanced_portfolio
+ ])
+ st.dataframe(metrics_df, hide_index=True)
+ else:
+ st.error("Could not generate balanced growth portfolio.")
+
+ # Display Income Focus Strategy
+ with strategy_tabs[1]:
+ st.write("### Income Focus Strategy")
+ st.write("Optimized for higher dividend income with lower risk, suitable for income-focused investors.")
+ if income_portfolio:
+ portfolio_df = pd.DataFrame(income_portfolio)
+ portfolio_df['Allocation (%)'] = portfolio_df['allocation'] * 100
+ portfolio_df['Amount ($)'] = portfolio_df['amount']
+
+ st.dataframe(
+ portfolio_df[['ticker', 'name', 'Allocation (%)', 'Amount ($)']],
+ hide_index=True
+ )
+
+ # Display metrics
+ metrics_df = pd.DataFrame([
+ {
+ 'Ticker': etf['ticker'],
+ 'Expense Ratio (%)': etf['metrics']['expense_ratio'] * 100,
+ 'AUM ($B)': etf['metrics']['aum'] / 1e9,
+ 'Volatility (%)': etf['metrics']['volatility'] * 100,
+ 'Max Drawdown (%)': etf['metrics']['max_drawdown'] * 100,
+ 'Sharpe Ratio': etf['metrics']['sharpe_ratio'],
+ 'Dividend Yield (%)': etf['metrics']['dividend_yield'] * 100
+ }
+ for etf in income_portfolio
+ ])
+ st.dataframe(metrics_df, hide_index=True)
+ else:
+ st.error("Could not generate income focus portfolio.")
+
+ # Display Growth Focus Strategy
+ with strategy_tabs[2]:
+ st.write("### Growth Focus Strategy")
+ st.write("Optimized for capital appreciation with higher risk tolerance, suitable for growth investors.")
+ if growth_portfolio:
+ portfolio_df = pd.DataFrame(growth_portfolio)
+ portfolio_df['Allocation (%)'] = portfolio_df['allocation'] * 100
+ portfolio_df['Amount ($)'] = portfolio_df['amount']
+
+ st.dataframe(
+ portfolio_df[['ticker', 'name', 'Allocation (%)', 'Amount ($)']],
+ hide_index=True
+ )
+
+ # Display metrics
+ metrics_df = pd.DataFrame([
+ {
+ 'Ticker': etf['ticker'],
+ 'Expense Ratio (%)': etf['metrics']['expense_ratio'] * 100,
+ 'AUM ($B)': etf['metrics']['aum'] / 1e9,
+ 'Volatility (%)': etf['metrics']['volatility'] * 100,
+ 'Max Drawdown (%)': etf['metrics']['max_drawdown'] * 100,
+ 'Sharpe Ratio': etf['metrics']['sharpe_ratio'],
+ 'Dividend Yield (%)': etf['metrics']['dividend_yield'] * 100
+ }
+ for etf in growth_portfolio
+ ])
+ st.dataframe(metrics_df, hide_index=True)
+ else:
+ st.error("Could not generate growth focus portfolio.")
+
+ # Display Risk-Adjusted Strategy
+ with strategy_tabs[3]:
+ st.write("### Risk-Adjusted Strategy")
+ st.write(f"Optimized for your specific risk tolerance ({risk_tolerance}), balancing growth and income.")
+ if risk_adjusted_portfolio:
+ portfolio_df = pd.DataFrame(risk_adjusted_portfolio)
+ portfolio_df['Allocation (%)'] = portfolio_df['allocation'] * 100
+ portfolio_df['Amount ($)'] = portfolio_df['amount']
+
+ st.dataframe(
+ portfolio_df[['ticker', 'name', 'Allocation (%)', 'Amount ($)']],
+ hide_index=True
+ )
+
+ # Display metrics
+ metrics_df = pd.DataFrame([
+ {
+ 'Ticker': etf['ticker'],
+ 'Expense Ratio (%)': etf['metrics']['expense_ratio'] * 100,
+ 'AUM ($B)': etf['metrics']['aum'] / 1e9,
+ 'Volatility (%)': etf['metrics']['volatility'] * 100,
+ 'Max Drawdown (%)': etf['metrics']['max_drawdown'] * 100,
+ 'Sharpe Ratio': etf['metrics']['sharpe_ratio'],
+ 'Dividend Yield (%)': etf['metrics']['dividend_yield'] * 100
+ }
+ for etf in risk_adjusted_portfolio
+ ])
+ st.dataframe(metrics_df, hide_index=True)
+ else:
+ st.error("Could not generate risk-adjusted portfolio.")
+
+ # Add buttons to apply each strategy
+ st.write("### Apply Strategy")
+ col1, col2, col3, col4 = st.columns(4)
+
+ with col1:
+ if st.button("Apply Balanced Growth", key="apply_balanced"):
+ if balanced_portfolio:
+ st.session_state.etf_allocations = [
+ {"ticker": etf['ticker'], "allocation": etf['allocation'] * 100}
+ for etf in balanced_portfolio
+ ]
+ st.success("Applied Balanced Growth strategy!")
+ st.rerun()
+
+ with col2:
+ if st.button("Apply Income Focus", key="apply_income"):
+ if income_portfolio:
+ st.session_state.etf_allocations = [
+ {"ticker": etf['ticker'], "allocation": etf['allocation'] * 100}
+ for etf in income_portfolio
+ ]
+ st.success("Applied Income Focus strategy!")
+ st.rerun()
+
+ with col3:
+ if st.button("Apply Growth Focus", key="apply_growth"):
+ if growth_portfolio:
+ st.session_state.etf_allocations = [
+ {"ticker": etf['ticker'], "allocation": etf['allocation'] * 100}
+ for etf in growth_portfolio
+ ]
+ st.success("Applied Growth Focus strategy!")
+ st.rerun()
+
+ with col4:
+ if st.button("Apply Risk-Adjusted", key="apply_risk_adjusted"):
+ if risk_adjusted_portfolio:
+ st.session_state.etf_allocations = [
+ {"ticker": etf['ticker'], "allocation": etf['allocation'] * 100}
+ for etf in risk_adjusted_portfolio
+ ]
+ st.success("Applied Risk-Adjusted strategy!")
+ st.rerun()
- if portfolio:
- # Display portfolio suggestions
- st.success("Portfolio suggestions generated successfully!")
-
- # Create a DataFrame for better display
- portfolio_df = pd.DataFrame(portfolio)
- portfolio_df['Allocation (%)'] = portfolio_df['allocation'] * 100
- portfolio_df['Amount ($)'] = portfolio_df['amount']
-
- # Display portfolio summary
- st.write("### Portfolio Summary")
- st.dataframe(
- portfolio_df[['ticker', 'name', 'Allocation (%)', 'Amount ($)']],
- hide_index=True
- )
-
- # Display detailed metrics
- st.write("### Detailed Metrics")
- metrics_df = pd.DataFrame([
- {
- 'Ticker': etf['ticker'],
- 'Expense Ratio (%)': etf['metrics']['expense_ratio'] * 100,
- 'AUM ($B)': etf['metrics']['aum'] / 1e9,
- 'Volatility (%)': etf['metrics']['volatility'] * 100,
- 'Max Drawdown (%)': etf['metrics']['max_drawdown'] * 100,
- 'Sharpe Ratio': etf['metrics']['sharpe_ratio'],
- 'Dividend Yield (%)': etf['metrics']['dividend_yield'] * 100
- }
- for etf in portfolio
- ])
- st.dataframe(metrics_df, hide_index=True)
-
- # Display portfolio allocation chart
- st.write("### Portfolio Allocation")
- fig = px.pie(
- portfolio_df,
- values='Allocation (%)',
- names='ticker',
- title='Portfolio Allocation by ETF'
- )
- st.plotly_chart(fig)
- else:
- st.error("No portfolio suggestions could be generated. Please try different parameters.")
-
except ValueError as e:
st.error(str(e))
except Exception as e: