updating the AI Suggestions yab
This commit is contained in:
parent
f7cf624721
commit
27ef418f84
@ -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("""
|
||||
<style>
|
||||
.ticker-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ticker-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: #2ecc71;
|
||||
font-size: 1.1em;
|
||||
font-weight: 500;
|
||||
}
|
||||
.ticker-close {
|
||||
margin-left: 2px;
|
||||
cursor: pointer;
|
||||
font-size: 1.1em;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.ticker-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
""", 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"""
|
||||
<div style="display: flex; align-items: center; gap: 2px; margin-bottom: -15px;">
|
||||
<span style="color: #2ecc71; font-weight: 500;">{etf['ticker']}</span>
|
||||
</div>
|
||||
""", 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"<div class='ticker-item'>{etf['ticker']}</div>", 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("""
|
||||
<style>
|
||||
.stTextInput input {
|
||||
color: #2ecc71 !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
</style>
|
||||
""", 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,29 +2863,68 @@ 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)
|
||||
|
||||
if portfolio:
|
||||
# Display portfolio suggestions
|
||||
st.success("Portfolio suggestions generated successfully!")
|
||||
# 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)
|
||||
|
||||
# Create a DataFrame for better display
|
||||
portfolio_df = pd.DataFrame(portfolio)
|
||||
# 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']
|
||||
|
||||
# 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")
|
||||
# Display metrics
|
||||
metrics_df = pd.DataFrame([
|
||||
{
|
||||
'Ticker': etf['ticker'],
|
||||
@ -2905,21 +2935,148 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
'Sharpe Ratio': etf['metrics']['sharpe_ratio'],
|
||||
'Dividend Yield (%)': etf['metrics']['dividend_yield'] * 100
|
||||
}
|
||||
for etf in portfolio
|
||||
for etf in balanced_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.")
|
||||
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()
|
||||
|
||||
except ValueError as e:
|
||||
st.error(str(e))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user