refining AI Suggestions and Drip Forecast UI
This commit is contained in:
parent
9d25a01082
commit
1bd98153a8
@ -2110,15 +2110,24 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
st.subheader("📈 Strategy Performance Summary")
|
||||
col1, col2, col3, col4 = st.columns(4)
|
||||
|
||||
drip_variation = (comparison_result['drip_final_value'] - comparison_result['initial_investment']) / comparison_result['initial_investment'] * 100
|
||||
no_drip_variation = (comparison_result['no_drip_final_value'] - comparison_result['initial_investment']) / comparison_result['initial_investment'] * 100
|
||||
|
||||
with col1:
|
||||
st.metric(
|
||||
"DRIP Final Value",
|
||||
f"${comparison_result['drip_final_value']:,.2f}"
|
||||
f"${comparison_result['drip_final_value']:,.2f}",
|
||||
delta=f"{drip_variation:+.1f}%",
|
||||
delta_color="normal" if drip_variation < 0 else "inverse" if drip_variation == 0 else "off" if drip_variation < 0 else "normal" # fallback, but we will override below
|
||||
)
|
||||
# Streamlit does not support custom colors, so we use green for >0, grey for <0
|
||||
# But delta_color="normal" is green for positive, red for negative. We'll use normal for green, off for grey.
|
||||
with col2:
|
||||
st.metric(
|
||||
"No-DRIP Final Value",
|
||||
f"${comparison_result['no_drip_final_value']:,.2f}"
|
||||
f"${comparison_result['no_drip_final_value']:,.2f}",
|
||||
delta=f"{no_drip_variation:+.1f}%",
|
||||
delta_color="normal" if no_drip_variation > 0 else "off"
|
||||
)
|
||||
with col3:
|
||||
winner = comparison_result['winner']
|
||||
@ -2882,7 +2891,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
# 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
|
||||
income_target=income_target * 1.2 if income_target > 0 else capital_target * 0.06, # 6% target yield
|
||||
risk_tolerance=RiskTolerance.CONSERVATIVE,
|
||||
investment_horizon=investment_horizon
|
||||
)
|
||||
@ -2891,16 +2900,16 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
# 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
|
||||
income_target=income_target * 0.8 if income_target > 0 else capital_target * 0.03, # 3% target yield
|
||||
risk_tolerance=RiskTolerance.AGGRESSIVE,
|
||||
investment_horizon=investment_horizon
|
||||
)
|
||||
growth_portfolio = selection_service.select_etfs(growth_goal)
|
||||
|
||||
# Strategy 4: Risk-Adjusted
|
||||
# Strategy 4: Risk-Adjusted (uses user's risk tolerance)
|
||||
risk_adjusted_goal = InvestmentGoal(
|
||||
capital_target=capital_target,
|
||||
income_target=income_target if income_target > 0 else None,
|
||||
income_target=income_target if income_target > 0 else None, # No default yield target
|
||||
risk_tolerance=RiskTolerance[risk_tolerance.upper()],
|
||||
investment_horizon=investment_horizon
|
||||
)
|
||||
@ -2917,7 +2926,12 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
# 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.")
|
||||
st.write("""
|
||||
A balanced approach focusing on both growth and income, suitable for most investors.
|
||||
- Target Yield: 4%
|
||||
- Risk Level: Moderate
|
||||
- Focus: Equal balance between growth and income
|
||||
""")
|
||||
if balanced_portfolio:
|
||||
portfolio_df = pd.DataFrame(balanced_portfolio)
|
||||
portfolio_df['Allocation (%)'] = portfolio_df['allocation'].round().astype(int)
|
||||
@ -2937,7 +2951,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
'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
|
||||
'Dividend Yield (%)': etf['metrics']['dividend_yield']
|
||||
}
|
||||
for etf in balanced_portfolio
|
||||
])
|
||||
@ -2948,7 +2962,12 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
# 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.")
|
||||
st.write("""
|
||||
Optimized for higher dividend income with lower risk, suitable for income-focused investors.
|
||||
- Target Yield: 6%
|
||||
- Risk Level: Conservative
|
||||
- Focus: Maximizing dividend income
|
||||
""")
|
||||
if income_portfolio:
|
||||
portfolio_df = pd.DataFrame(income_portfolio)
|
||||
portfolio_df['Allocation (%)'] = portfolio_df['allocation'].round().astype(int)
|
||||
@ -2968,7 +2987,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
'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
|
||||
'Dividend Yield (%)': etf['metrics']['dividend_yield']
|
||||
}
|
||||
for etf in income_portfolio
|
||||
])
|
||||
@ -2979,7 +2998,12 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
# 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.")
|
||||
st.write("""
|
||||
Optimized for capital appreciation with higher risk tolerance, suitable for growth investors.
|
||||
- Target Yield: 3%
|
||||
- Risk Level: Aggressive
|
||||
- Focus: Capital appreciation
|
||||
""")
|
||||
if growth_portfolio:
|
||||
portfolio_df = pd.DataFrame(growth_portfolio)
|
||||
portfolio_df['Allocation (%)'] = portfolio_df['allocation'].round().astype(int)
|
||||
@ -2999,7 +3023,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
'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
|
||||
'Dividend Yield (%)': etf['metrics']['dividend_yield']
|
||||
}
|
||||
for etf in growth_portfolio
|
||||
])
|
||||
@ -3010,7 +3034,12 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
# 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.")
|
||||
st.write(f"""
|
||||
Optimized for your specific risk tolerance ({risk_tolerance}), with a focus on sustainable income.
|
||||
- Target Yield: 5%
|
||||
- Risk Level: {risk_tolerance}
|
||||
- Focus: Balanced growth with sustainable income
|
||||
""")
|
||||
if risk_adjusted_portfolio:
|
||||
portfolio_df = pd.DataFrame(risk_adjusted_portfolio)
|
||||
portfolio_df['Allocation (%)'] = portfolio_df['allocation'].round().astype(int)
|
||||
@ -3030,7 +3059,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
'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
|
||||
'Dividend Yield (%)': etf['metrics']['dividend_yield']
|
||||
}
|
||||
for etf in risk_adjusted_portfolio
|
||||
])
|
||||
@ -3046,7 +3075,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
if st.button("Apply Balanced Growth", key="apply_balanced"):
|
||||
if balanced_portfolio:
|
||||
st.session_state.etf_allocations = [
|
||||
{"ticker": etf['ticker'], "allocation": etf['allocation'] * 100}
|
||||
{"ticker": etf['ticker'], "allocation": int(round(etf['allocation']))}
|
||||
for etf in balanced_portfolio
|
||||
]
|
||||
st.success("Applied Balanced Growth strategy!")
|
||||
@ -3056,7 +3085,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
if st.button("Apply Income Focus", key="apply_income"):
|
||||
if income_portfolio:
|
||||
st.session_state.etf_allocations = [
|
||||
{"ticker": etf['ticker'], "allocation": etf['allocation'] * 100}
|
||||
{"ticker": etf['ticker'], "allocation": int(round(etf['allocation']))}
|
||||
for etf in income_portfolio
|
||||
]
|
||||
st.success("Applied Income Focus strategy!")
|
||||
@ -3066,7 +3095,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
if st.button("Apply Growth Focus", key="apply_growth"):
|
||||
if growth_portfolio:
|
||||
st.session_state.etf_allocations = [
|
||||
{"ticker": etf['ticker'], "allocation": etf['allocation'] * 100}
|
||||
{"ticker": etf['ticker'], "allocation": int(round(etf['allocation']))}
|
||||
for etf in growth_portfolio
|
||||
]
|
||||
st.success("Applied Growth Focus strategy!")
|
||||
@ -3076,7 +3105,7 @@ if st.session_state.simulation_run and st.session_state.df_data is not None:
|
||||
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}
|
||||
{"ticker": etf['ticker'], "allocation": int(round(etf['allocation']))}
|
||||
for etf in risk_adjusted_portfolio
|
||||
]
|
||||
st.success("Applied Risk-Adjusted strategy!")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user