To address the problem of improving and enhancing the Performance Comparison Table, the following code segments from your portfolio_optimizer.py are directly relevant. These segments handle the calculation of performance metrics, the creation of the performance statistics DataFrame, and the display of the Performance Comparison Table with appropriate styling.

1. Calculating Performance Metrics
The calculate_metrics function computes various performance metrics necessary for the comparison table. It ensures consistent data types and handles potential calculation issues gracefully.


def calculate_metrics(
    returns: pd.Series, 
    cum_returns: pd.Series, 
    rf: float = 0.02, 
    benchmark_returns: pd.Series = None
) -> dict:
    """
    Calculate portfolio performance metrics with consistent data types.
    
    Args:
        returns (pd.Series): Portfolio returns
        cum_returns (pd.Series): Cumulative returns
        rf (float): Risk-free rate
        benchmark_returns (pd.Series, optional): Benchmark returns for comparison
    
    Returns:
        dict: Dictionary of metrics with consistent data types
    """
    metrics = {}
    
    # Initialize with default values
    initial_balance = 10000.0
    metrics['Start Balance'] = initial_balance
    
    def safe_calculation(calculation, default=np.nan):
        """Helper function to safely perform calculations"""
        try:
            result = calculation()
            return result if not np.isinf(result) and not np.isnan(result) else default
        except Exception:
            return default

    if not cum_returns.empty and not returns.empty:
        # Basic portfolio metrics
        end_balance = safe_calculation(lambda: initial_balance * cum_returns.iloc[-1])
        years = (cum_returns.index[-1] - cum_returns.index[0]).days / 365.25
        
        metrics.update({
            'End Balance': end_balance,
            'Annualized Return (CAGR)': safe_calculation(
                lambda: (end_balance / initial_balance) ** (1 / years) - 1 if years > 0 else np.nan
            ),
            'Best Year': safe_calculation(
                lambda: returns.resample('Y').apply(lambda x: (1 + x).prod() - 1).max()
            ),
            'Worst Year': safe_calculation(
                lambda: returns.resample('Y').apply(lambda x: (1 + x).prod() - 1).min()
            ),
            'Arithmetic Mean (Monthly)': safe_calculation(
                lambda: returns.mean()
            ),
            'Arithmetic Mean (Annualized)': safe_calculation(
                lambda: returns.mean() * 252
            ),
            'Geometric Mean (Monthly)': safe_calculation(
                lambda: np.exp(np.log1p(returns).mean()) - 1
            ),
            'Geometric Mean (Annualized)': safe_calculation(
                lambda: np.exp(np.log1p(returns).mean() * 252) - 1
            ),
            'Standard Deviation (Monthly)': safe_calculation(
                lambda: returns.std()
            ),
            'Standard Deviation (Annualized)': safe_calculation(
                lambda: returns.std() * np.sqrt(252)
            ),
            'Downside Deviation (Monthly)': safe_calculation(
                lambda: returns[returns < 0].std()
            ),
            'Maximum Drawdown': safe_calculation(
                lambda: drawdown(cum_returns)
            ),
            'Sharpe Ratio': safe_calculation(
                lambda: calculate_sharpe_ratio(returns, rf)
            ),
            'Sortino Ratio': safe_calculation(
                lambda: calculate_sortino_ratio(returns, rf)
            ),
            'Gain/Loss Ratio': safe_calculation(
                lambda: calculate_gain_loss_ratio(returns)
            ),
            'Skewness': safe_calculation(
                lambda: float(skew(returns))
            ),
            'Excess Kurtosis': safe_calculation(
                lambda: float(kurtosis(returns))
            ),
            'Safe Withdrawal Rate': safe_calculation(
                lambda: calculate_safe_withdrawal_rate(returns)
            ),
            'Perpetual Withdrawal Rate': safe_calculation(
                lambda: calculate_perpetual_withdrawal_rate(returns)
            ),
            'Positive Periods': safe_calculation(
                lambda: calculate_positive_periods(returns)
            )
        })
    else:
        # Set default values for empty data
        default_metrics = {
            'End Balance': np.nan,
            'Annualized Return (CAGR)': np.nan,
            'Best Year': np.nan,
            'Worst Year': np.nan,
            'Arithmetic Mean (Monthly)': np.nan,
            'Arithmetic Mean (Annualized)': np.nan,
            'Geometric Mean (Monthly)': np.nan,
            'Geometric Mean (Annualized)': np.nan,
            'Standard Deviation (Monthly)': np.nan,
            'Standard Deviation (Annualized)': np.nan,
            'Downside Deviation (Monthly)': np.nan,
            'Maximum Drawdown': np.nan,
            'Sharpe Ratio': np.nan,
            'Sortino Ratio': np.nan,
            'Gain/Loss Ratio': np.nan,
            'Skewness': np.nan,
            'Excess Kurtosis': np.nan,
            'Safe Withdrawal Rate': np.nan,
            'Perpetual Withdrawal Rate': np.nan,
            'Positive Periods': np.nan
        }
        metrics.update(default_metrics)

    # Benchmark-relative metrics
    if benchmark_returns is not None and not benchmark_returns.empty:
        metrics.update({
            'Benchmark Correlation': safe_calculation(
                lambda: returns.corr(benchmark_returns)
            ),
            'Beta': safe_calculation(
                lambda: calculate_beta(returns, benchmark_returns)
            ),
            'Alpha (annualized)': safe_calculation(
                lambda: calculate_alpha(returns, benchmark_returns, rf)
            ),
            'R2': safe_calculation(
                lambda: calculate_r_squared(returns, benchmark_returns)
            ),
            'Treynor Ratio': safe_calculation(
                lambda: calculate_treynor_ratio(returns, benchmark_returns, rf)
            ),
            'Calmar Ratio': safe_calculation(
                lambda: calculate_calmar_ratio(returns, cum_returns)
            ),
            'Modigliani–Modigliani Measure': safe_calculation(
                lambda: calculate_modigliani_miller(returns, benchmark_returns, rf)
            ),
            'Information Ratio': safe_calculation(
                lambda: calculate_information_ratio(returns, benchmark_returns)
            ),
            'Tracking Error': safe_calculation(
                lambda: calculate_tracking_error(returns, benchmark_returns)
            ),
            'Active Return': safe_calculation(
                lambda: calculate_active_return(returns, benchmark_returns)
            ),
            'Upside Capture Ratio': safe_calculation(
                lambda: calculate_capture_ratio(returns, benchmark_returns, upside=True)
            ),
            'Downside Capture Ratio': safe_calculation(
                lambda: calculate_capture_ratio(returns, benchmark_returns, upside=False)
            )
        })
    else:
        # Set default values for benchmark metrics
        benchmark_metrics = {
            'Benchmark Correlation': np.nan,
            'Beta': np.nan,
            'Alpha (annualized)': np.nan,
            'R2': np.nan,
            'Treynor Ratio': np.nan,
            'Calmar Ratio': np.nan,
            'Modigliani–Modigliani Measure': np.nan,
            'Information Ratio': np.nan,
            'Tracking Error': np.nan,
            'Active Return': np.nan,
            'Upside Capture Ratio': np.nan,
            'Downside Capture Ratio': np.nan
        }
        metrics.update(benchmark_metrics)

    return metrics
2. Creating the Performance Statistics DataFrame
The following functions create DataFrames that organize the calculated metrics for display. They handle both portfolio vs. benchmark and portfolio vs. portfolio comparisons.


def create_performance_stats_df(metrics, benchmark_metrics):
    """Creates a DataFrame for performance statistics."""
    return pd.DataFrame({
        'Metric': [
            'Start Balance', 'End Balance', 'Annualized Return (CAGR)',
            'Standard Deviation (Annualized)', 'Best Year', 'Worst Year',
            'Maximum Drawdown', 'Sharpe Ratio', 'Sortino Ratio', 'Benchmark Correlation'
        ],
        'Portfolio': [
            metrics.get('Start Balance', "N/A"),
            metrics.get('End Balance', "N/A"),
            metrics.get('Annualized Return (CAGR)', "N/A"),
            metrics.get('Standard Deviation (Annualized)', "N/A"),
            metrics.get('Best Year', "N/A"),
            metrics.get('Worst Year', "N/A"),
            metrics.get('Maximum Drawdown', "N/A"),
            metrics.get('Sharpe Ratio', "N/A"),
            metrics.get('Sortino Ratio', "N/A"),
            metrics.get('Benchmark Correlation', "N/A")
        ],
        'Benchmark': [
            benchmark_metrics.get('Start Balance', "N/A"),
            benchmark_metrics.get('End Balance', "N/A"),
            benchmark_metrics.get('Annualized Return (CAGR)', "N/A"),
            benchmark_metrics.get('Standard Deviation (Annualized)', "N/A"),
            benchmark_metrics.get('Best Year', "N/A"),
            benchmark_metrics.get('Worst Year', "N/A"),
            benchmark_metrics.get('Maximum Drawdown', "N/A"),
            benchmark_metrics.get('Sharpe Ratio', "N/A"),
            benchmark_metrics.get('Sortino Ratio', "N/A"),
            benchmark_metrics.get('Benchmark Correlation', "N/A")
        ]
    }).set_index('Metric')

def create_performance_stats_df_portfolio_vs_portfolio(metrics_a, metrics_b, portfolio1, portfolio2):
    """Creates a refined DataFrame for Portfolio vs Portfolio performance statistics."""
    metrics = [
        'Annualized Return (CAGR)',
        'Sharpe Ratio',
        'Sortino Ratio',
        'Maximum Drawdown',
        'Beta',
        'Alpha (annualized)',
        'Information Ratio'
    ]

    data = {
        'Metric': metrics,
        portfolio1: [metrics_a.get(metric, "N/A") for metric in metrics],
        portfolio2: [metrics_b.get(metric, "N/A") for metric in metrics]
    }

    performance_df = pd.DataFrame(data)
    performance_df.set_index('Metric', inplace=True)
    return performance_df

def create_advanced_metrics_df(metrics, benchmark_metrics):
    """Creates a DataFrame for advanced metrics."""
    return pd.DataFrame({
        'Metric': list(metrics.keys()),
        'Portfolio': list(metrics.values()),
        'Benchmark': list(benchmark_metrics.values())
    }).set_index('Metric')

def create_advanced_metrics_df_portfolio_vs_portfolio(metrics_a, metrics_b, portfolio1, portfolio2):
    """Creates a refined DataFrame for Portfolio vs Portfolio advanced metrics."""
    metrics = [
        'Beta',
        'Alpha (annualized)',
        'Information Ratio',
        'Modigliani–Modigliani Measure',
        'Tracking Error',
        'Upside Capture Ratio',
        'Downside Capture Ratio'
    ]

    data = {
        'Metric': metrics,
        portfolio1: [metrics_a.get(metric, "N/A") for metric in metrics],
        portfolio2: [metrics_b.get(metric, "N/A") for metric in metrics]
    }

    advanced_metrics_df = pd.DataFrame(data)
    advanced_metrics_df.set_index('Metric', inplace=True)
    return advanced_metrics_df
3. Highlighting Better Performance in the Table
The highlight_better_performance function styles the DataFrame to visually distinguish which portfolio has better metrics. It applies background colors based on performance comparisons.


def highlight_better_performance(portfolio1, portfolio2):
    """
    Creates a styling function for comparing two portfolios.
    
    Args:
        portfolio1 (str): Name of the first portfolio
        portfolio2 (str): Name of the second portfolio
        
    Returns:
        function: A styling function that can be used with DataFrame.style.apply()
    """
    def _style_row(row):
        styles = [''] * len(row)
        
        # Check if both portfolios exist in the row
        if portfolio1 in row.index and portfolio2 in row.index:
            val1 = row[portfolio1]
            val2 = row[portfolio2]
            
            # Convert string values to float if possible
            try:
                if isinstance(val1, str):
                    val1 = float(val1.strip('%').strip('$').replace(',', ''))
                if isinstance(val2, str):
                    val2 = float(val2.strip('%').strip('$').replace(',', ''))
                
                # Only proceed if both values are numeric
                if isinstance(val1, (int, float)) and isinstance(val2, (int, float)):
                    if 'Drawdown' in row.name or 'Risk' in row.name:
                        better = val1 < val2
                    else:
                        better = val1 > val2
                    
                    # Find the column indices for the portfolios
                    idx1 = row.index.get_loc(portfolio1)
                    idx2 = row.index.get_loc(portfolio2)
                    
                    # Apply styling
                    styles[idx1] = 'background-color: #d4f7d4' if better else 'background-color: #f7d4d4'
                    styles[idx2] = 'background-color: #d4f7d4' if not better else 'background-color: #f7d4d4'
            except (ValueError, TypeError):
                pass  # Skip if conversion fails
                
        return styles
    
    return _style_row 
4. Displaying the Performance Comparison Table
The display_portfolio_vs_benchmark function handles the creation and styling of the Performance Comparison Table when comparing a portfolio against a benchmark. It utilizes the previously defined functions to calculate metrics, create DataFrames, and apply styling.


def display_portfolio_vs_benchmark(results, portfolio_name):
    # Extract data from results
    returns = results['returns']
    cum_returns = results['cum_returns']
    weights = results['weights']
    price_data = results['price_data']
    available_selected = results['available_selected']
    metrics = results['metrics']
    benchmark_metrics = results['benchmark_metrics']
    benchmark_returns = results['benchmark_returns']
    benchmark_cum_returns = results['benchmark_cum_returns']

    # Define a consistent theme for all plots
    THEMES = {
        'plotly_dark': 'plotly_dark',
        'plotly_light': 'plotly_white'
    }
    selected_theme = THEMES.get('plotly_dark')  # Change as needed

    # Create tabs for better organization
    main_tab, metrics_tab, risk_tab, analysis_tab, insights_tab = st.tabs([
        "📈 Main Charts", "📊 Performance Metrics", "🎯 Risk Analysis", "🔍 Deep Analysis", "🧠 Metric-Based Insights"
    ])

    with main_tab:
        st.header("🔹 Portfolio vs Benchmark Overview")
        col1, col2 = st.columns([2, 1])
        with col1:
            st.subheader("Portfolio Composition")
            fig_composition = px.pie(
                values=weights,
                names=price_data.columns,
                title="Current Portfolio Allocation",
                template=selected_theme,
                hole=0.4
            )
            fig_composition.update_traces(textinfo='percent+label')
            st.plotly_chart(fig_composition, use_container_width=True)

        with col2:
            st.subheader("Key Performance Indicators")
            # Format metrics here, ensuring numerical operations are valid
            annualized_cagr = metrics.get('Annualized Return (CAGR)', None)
            if isinstance(annualized_cagr, (int, float)) and not np.isnan(annualized_cagr):
                annualized_return = f"{annualized_cagr * 100:.2f}%"
            else:
                annualized_return = "N/A"

            # Similarly format other metrics
            total_return = f"{(cum_returns.iloc[-1] - 1) * 100:.2f}%" if not cum_returns.empty else "N/A"
            sharpe_ratio = f"{metrics.get('Sharpe Ratio', 'N/A')}" if 'Sharpe Ratio' in metrics else "N/A"
            max_drawdown = f"{metrics.get('Maximum Drawdown', 0):.2f}%" if 'Maximum Drawdown' in metrics else "N/A"

            metrics_display = {
                "Total Return": total_return,
                "Annualized Return": annualized_return,
                "Sharpe Ratio": sharpe_ratio,
                "Max Drawdown": max_drawdown
            }
            for metric, value in metrics_display.items():
                st.metric(metric, value)

        # Performance Metrics Tab
        with metrics_tab:
            st.header("📊 Key Performance Metrics")
            st.subheader("Performance Comparison Table")

            # Define metrics separately
            common_metrics = [
                'Annualized Return (CAGR)',
                'Maximum Drawdown',
                'Sharpe Ratio',
                'Sortino Ratio',
                'Standard Deviation (Annualized)',
                'Beta',
                'Information Ratio',
                'R2',
                'Tracking Error',
                'Upside Capture Ratio',
                'Downside Capture Ratio',
                'Best Year',
                'Worst Year',
                'Calmar Ratio'
            ]

            portfolio_only_metrics = [
                'Alpha (annualized)'
            ]

            # Filter metrics
            filtered_portfolio_metrics = {k: v for k, v in metrics.items() if k in common_metrics + portfolio_only_metrics}
            filtered_benchmark_metrics = {k: v for k, v in benchmark_metrics.items() if k in common_metrics}

            # Create DataFrame for Portfolio Metrics
            portfolio_metrics_df = pd.DataFrame(filtered_portfolio_metrics.items(), columns=['Metric', 'Portfolio'])
            # Create DataFrame for Benchmark Metrics
            benchmark_metrics_df = pd.DataFrame(filtered_benchmark_metrics.items(), columns=['Metric', 'Benchmark'])

            # Merge on common metrics
            metrics_comparison = pd.merge(portfolio_metrics_df, benchmark_metrics_df, on='Metric', how='left')

            # Add Portfolio-Only Metrics with 'N/A' for Benchmark
            if portfolio_only_metrics:
                portfolio_only_df = pd.DataFrame({
                    'Metric': portfolio_only_metrics,
                    'Portfolio': [filtered_portfolio_metrics.get(k, "N/A") for k in portfolio_only_metrics],
                    'Benchmark': ["N/A"] * len(portfolio_only_metrics)
                })
                metrics_comparison = pd.concat([metrics_comparison, portfolio_only_df], ignore_index=True)

            # Define which metrics are percentage-based
            percentage_metrics = [
                'Annualized Return (CAGR)',
                'Maximum Drawdown',
                'Standard Deviation (Annualized)',
                'Alpha (annualized)',
                'Tracking Error',
                'Best Year',
                'Worst Year',
                'Upside Capture Ratio',
                'Downside Capture Ratio'
            ]

            # Style the metrics table
            def highlight_better(row):
                styles = [''] * len(row)
                portfolio_val = row["Portfolio"]
                benchmark_val = row["Benchmark"]

                # Skip if Portfolio is 'N/A'
                if portfolio_val == "N/A":
                    return styles

                try:
                    # Convert string values to float if possible
                    if isinstance(portfolio_val, str):
                        portfolio_num = float(portfolio_val.strip('%').strip('$').replace(',', ''))
                    else:
                        portfolio_num = portfolio_val

                    if isinstance(benchmark_val, str):
                        benchmark_num = float(benchmark_val.strip('%').strip('$').replace(',', ''))
                    elif benchmark_val == "N/A":
                        benchmark_num = None
                    else:
                        benchmark_num = benchmark_val

                    # Determine if higher is better or lower is better based on metric name
                    metric_name = row['Metric']
                    lower_is_better = any(keyword in metric_name for keyword in [
                        'Drawdown', 'Deviation', 'Tracking Error', 'Downside Capture Ratio'
                    ])
                    if benchmark_num is not None:
                        better = portfolio_num < benchmark_num if lower_is_better else portfolio_num > benchmark_num

                        # Highlight the better performance
                        styles[1] = 'background-color: #d4f7d4' if better else 'background-color: #f7d4d4'
                        styles[2] = 'background-color: #d4f7d4' if not better else 'background-color: #f7d4d4'
                except (ValueError, TypeError):
                    pass  # Skip if conversion fails

                return styles

            def custom_formatter(x, metric):
                try:
                    # Attempt to convert to float after stripping possible symbols
                    if x == "N/A":
                        return "N/A"
                    value = float(str(x).strip('%').strip('$').replace(',', ''))
                    if metric in percentage_metrics:
                        return f"{value:.2f}%"
                    else:
                        return f"{value:.2f}"
                except (ValueError, TypeError):
                    return "N/A"  # Return 'N/A' if conversion fails

            # Apply formatter row-wise to access metric name
            def row_formatter(row):
                metric = row['Metric']
                formatted = {}
                for col in ['Portfolio', 'Benchmark']:
                    formatted[col] = custom_formatter(row[col], metric)
                return pd.Series(formatted)

            # Apply the row_formatter to the 'Portfolio' and 'Benchmark' columns
            formatted_metrics = metrics_comparison.apply(row_formatter, axis=1)
            metrics_comparison[['Portfolio', 'Benchmark']] = formatted_metrics[['Portfolio', 'Benchmark']]

            # Apply the highlight function to style the rows
            styled_metrics = metrics_comparison.style.apply(
                highlight_better,
                axis=1
            ).format({
                'Portfolio': lambda x: x,
                'Benchmark': lambda x: x
            })

            # Add metric explanations
            metric_explanations = {
                'Annualized Return (CAGR)': 'Compound Annual Growth Rate - The geometric mean of portfolio returns',
                'Maximum Drawdown': 'Largest peak-to-trough decline',
                'Sharpe Ratio': 'Risk-adjusted return relative to risk-free rate',
                'Sortino Ratio': 'Risk-adjusted return focusing on downside volatility',
                'Standard Deviation (Annualized)': 'Measure of portfolio volatility',
                'Beta': 'Portfolio sensitivity to market movements',
                'Alpha (annualized)': 'Excess return compared to benchmark',
                'Information Ratio': 'Risk-adjusted excess returns vs benchmark',
                'R2': 'How well portfolio returns are explained by benchmark',
                'Tracking Error': 'Standard deviation of portfolio vs benchmark difference',
                'Upside Capture Ratio': 'Performance relative to benchmark in up markets',
                'Downside Capture Ratio': 'Performance relative to benchmark in down markets',
                'Best Year': 'Highest annual return',
                'Worst Year': 'Lowest annual return',
                'Calmar Ratio': 'Return relative to maximum drawdown'
            }

            # Display the metrics table
            col1, col2 = st.columns([2, 1])
            with col1:
                st.dataframe(styled_metrics, height=400)

            with col2:
                with st.expander("📖 Metric Definitions", expanded=True):
                    for metric, explanation in metric_explanations.items():
                        st.markdown(f"**{metric}**")
                        st.markdown(f"_{explanation}_")
                        st.markdown("---")
5. Displaying Backtest Results
The display_backtest_results function orchestrates the display of backtest outcomes, directing to specific functions based on the comparison type.


def display_backtest_results(results, comparison_type, portfolio1_name, portfolio2_name=None):
    # Do not pre-format metrics here
    if comparison_type == "Portfolio vs Benchmark":
        display_portfolio_vs_benchmark(results, portfolio1_name)
    elif comparison_type == "Portfolio vs Portfolio":
        display_portfolio_vs_portfolio(results, portfolio1_name, portfolio2_name)
6. Display Portfolio vs Portfolio (For Reference)
While your primary focus is on the Portfolio vs Benchmark table, here's a similar function for Portfolio vs Portfolio comparisons. This ensures consistency across different comparison types.


def display_portfolio_vs_portfolio(results, portfolio1_name, portfolio2_name):
    """Displays comparison between two portfolios with enhanced UI/UX."""
    # Extract data from results
    returns_a = results.get('returns_a', pd.Series(dtype=float))
    returns_b = results.get('returns_b', pd.Series(dtype=float))
    cum_returns_a = results.get('cum_returns_a', pd.Series(dtype=float))
    cum_returns_b = results.get('cum_returns_b', pd.Series(dtype=float))
    weights_a = results.get('weights_a', [])
    weights_b = results.get('weights_b', [])
    price_data_a = results.get('price_data_a', pd.DataFrame())
    price_data_b = results.get('price_data_b', pd.DataFrame())
    metrics_a = results.get('metrics_a', {})
    metrics_b = results.get('metrics_b', {})

    # Define available_a and available_b based on price data columns
    available_a = list(price_data_a.columns)
    available_b = list(price_data_b.columns)

    # Ensure that available_a and available_b are not empty
    if not available_a:
        st.error(f"No available data for Portfolio '{portfolio1}'.")
        return
    if not available_b:
        st.error(f"No available data for Portfolio '{portfolio2}'.")
        return

    # Define a consistent theme for all plots
    THEMES = {
        'plotly_dark': 'plotly_dark',
        'plotly_light': 'plotly_white'
    }
    selected_theme = THEMES.get('plotly_light')  # Change as needed

    # Create tabs for better organization
    overview_tab, comparison_tab, risk_tab, analysis_tab = st.tabs([
        "📊 Overview", "🔄 Comparison", "🎯 Risk Analysis", "🔍 Deep Analysis"
    ])

    with overview_tab:
        # Overview content...
        pass

    with comparison_tab:
        # Performance Metrics Comparison content...
        pass

    with risk_tab:
        # Risk Analysis content...
        pass

    with analysis_tab:
        # Deep Analysis content...
        pass
7. Helper Functions for Metrics Calculation
Ensure that all helper functions used within the metric calculations are defined and handle potential nan or inf values appropriately.


def calculate_sharpe_ratio(returns: pd.Series, rf: float = 0.02) -> float:
    """
    Calculate the Sharpe Ratio for a given set of returns.

    Parameters:
    - returns (pd.Series): Daily returns of the portfolio.
    - rf (float): Risk-free rate (default is 2%).

    Returns:
    - float: Sharpe Ratio.
    """
    excess_return = returns.mean() * 252 - rf
    std_dev = returns.std() * np.sqrt(252)
    return excess_return / std_dev if std_dev != 0 else np.nan

def calculate_sortino_ratio(returns: pd.Series, rf: float = 0.02) -> float:
    """
    Calculate the Sortino Ratio for a given set of returns.

    Parameters:
    - returns (pd.Series): Daily returns of the portfolio.
    - rf (float): Risk-free rate (default is 2%).

    Returns:
    - float: Sortino Ratio.
    """
    excess_return = returns.mean() * 252 - rf
    downside_std = returns[returns < 0].std() * np.sqrt(252)
    return excess_return / downside_std if downside_std != 0 else np.nan

def calculate_beta(returns: pd.Series, benchmark_returns: pd.Series) -> float:
    """
    Calculate the Beta of the portfolio relative to the benchmark.

    Parameters:
    - returns (pd.Series): Daily returns of the portfolio.
    - benchmark_returns (pd.Series): Daily returns of the benchmark.

    Returns:
    - float: Beta value.
    """
    if returns.empty or benchmark_returns.empty:
        return np.nan
    covariance_matrix = np.cov(returns, benchmark_returns)
    covariance = covariance_matrix[0, 1]
    benchmark_variance = covariance_matrix[1, 1]
    return covariance / benchmark_variance if benchmark_variance != 0 else np.nan

def calculate_alpha(returns: pd.Series, benchmark_returns: pd.Series, rf: float = 0.02) -> float:
    """
    Calculate the Alpha of the portfolio relative to the benchmark.

    Parameters:
    - returns (pd.Series): Daily returns of the portfolio.
    - benchmark_returns (pd.Series): Daily returns of the benchmark.
    - rf (float): Risk-free rate (default is 2%).

    Returns:
    - float: Alpha value.
    """
    beta = calculate_beta(returns, benchmark_returns)
    portfolio_return = returns.mean() * 252
    benchmark_return = benchmark_returns.mean() * 252
    return portfolio_return - (rf + beta * (benchmark_return - rf)) if not np.isnan(beta) else np.nan

def calculate_r_squared(returns: pd.Series, benchmark_returns: pd.Series) -> float:
    """
    Calculate the R-squared of the portfolio relative to the benchmark.

    Parameters:
    - returns (pd.Series): Daily returns of the portfolio.
    - benchmark_returns (pd.Series): Daily returns of the benchmark.

    Returns:
    - float: R-squared value.
    """
    if returns.empty or benchmark_returns.empty:
        return np.nan
    covariance = np.cov(returns, benchmark_returns)
    var_port = covariance[0,0]
    var_bench = covariance[1,1]
    cov = covariance[0,1]
    return (cov ** 2) / (var_port * var_bench) if var_port !=0 and var_bench !=0 else np.nan

def calculate_information_ratio(returns: pd.Series, benchmark_returns: pd.Series) -> float:
    """
    Calculate the Information Ratio of the portfolio relative to the benchmark.

    Parameters:
    - returns (pd.Series): Daily returns of the portfolio.
    - benchmark_returns (pd.Series): Daily returns of the benchmark.

    Returns:
    - float: Information Ratio.
    """
    if returns.empty or benchmark_returns.empty:
        return np.nan
    active_return = (returns.mean() - benchmark_returns.mean()) * 252
    tracking_error = calculate_tracking_error(returns, benchmark_returns)
    return active_return / tracking_error if tracking_error != 0 else np.nan

def calculate_tracking_error(returns: pd.Series, benchmark_returns: pd.Series) -> float:
    """
    Calculate the Tracking Error of the portfolio relative to the benchmark.

    Parameters:
    - returns (pd.Series): Daily returns of the portfolio.
    - benchmark_returns (pd.Series): Daily returns of the benchmark.

    Returns:
    - float: Tracking Error.
    """
    if returns.empty or benchmark_returns.empty:
        return np.nan
    return np.std((returns - benchmark_returns)) * np.sqrt(252)
8. Creating and Displaying the Styled Metrics DataFrame
This segment merges the calculated metrics into a DataFrame, applies formatting, and styles it using the highlight_better function for visual enhancement.


# Define which metrics are percentage-based
percentage_metrics = [
    'Annualized Return (CAGR)',
    'Maximum Drawdown',
    'Standard Deviation (Annualized)',
    'Alpha (annualized)',
    'Tracking Error',
    'Best Year',
    'Worst Year',
    'Upside Capture Ratio',
    'Downside Capture Ratio'
]

# Style the metrics table
def highlight_better(row):
    styles = [''] * len(row)
    portfolio_val = row["Portfolio"]
    benchmark_val = row["Benchmark"]

    # Skip if Portfolio is 'N/A'
    if portfolio_val == "N/A":
        return styles

    try:
        # Convert string values to float if possible
        if isinstance(portfolio_val, str):
            portfolio_num = float(portfolio_val.strip('%').strip('$').replace(',', ''))
        else:
            portfolio_num = portfolio_val

        if isinstance(benchmark_val, str):
            benchmark_num = float(benchmark_val.strip('%').strip('$').replace(',', ''))
        elif benchmark_val == "N/A":
            benchmark_num = None
        else:
            benchmark_num = benchmark_val

        # Determine if higher is better or lower is better based on metric name
        metric_name = row['Metric']
        lower_is_better = any(keyword in metric_name for keyword in [
            'Drawdown', 'Deviation', 'Tracking Error', 'Downside Capture Ratio'
        ])
        if benchmark_num is not None:
            better = portfolio_num < benchmark_num if lower_is_better else portfolio_num > benchmark_num

            # Highlight the better performance
            styles[1] = 'background-color: #d4f7d4' if better else 'background-color: #f7d4d4'
            styles[2] = 'background-color: #d4f7d4' if not better else 'background-color: #f7d4d4'
    except (ValueError, TypeError):
        pass  # Skip if conversion fails

    return styles

def custom_formatter(x, metric):
    try:
        # Attempt to convert to float after stripping possible symbols
        if x == "N/A":
            return "N/A"
        value = float(str(x).strip('%').strip('$').replace(',', ''))
        if metric in percentage_metrics:
            return f"{value:.2f}%"
        else:
            return f"{value:.2f}"
    except (ValueError, TypeError):
        return "N/A"  # Return 'N/A' if conversion fails

# Apply formatter row-wise to access metric name
def row_formatter(row):
    metric = row['Metric']
    formatted = {}
    for col in ['Portfolio', 'Benchmark']:
        formatted[col] = custom_formatter(row[col], metric)
    return pd.Series(formatted)

# Apply the row_formatter to the 'Portfolio' and 'Benchmark' columns
formatted_metrics = metrics_comparison.apply(row_formatter, axis=1)
metrics_comparison[['Portfolio', 'Benchmark']] = formatted_metrics[['Portfolio', 'Benchmark']]

# Apply the highlight function to style the rows
styled_metrics = metrics_comparison.style.apply(
    highlight_better,
    axis=1
).format({
    'Portfolio': lambda x: x,
    'Benchmark': lambda x: x
})
These extracted code segments collectively handle the calculation, organization, and presentation of the Performance Comparison Table. By refining these components, you can enhance the table's clarity, accuracy, and visual appeal, ensuring that users can effectively compare portfolio performance against benchmarks or other portfolios.

problem: improve and enhance by refining the Performance Comparison Table
Annualized Return (CAGR) 0.20% 0.11%
Best Year 0.49% 0.29%
Worst Year -0.10% -0.19%
Standard Deviation (Annualized) 0.21% 0.18%
Maximum Drawdown -0.36% -0.34%
Sharpe Ratio 0.89 0.56
Sortino Ratio 1.14 0.68
Beta nan nan
Alpha (annualized) nan% nan%
R2 nan nan
Calmar Ratio nan nan
Information Ratio nan nan
Tracking Error nan% nan%
Upside Capture Ratio nan% nan%
Downside Capture Ratio nan% nan%
Alpha (annualized) nan% N/A

if the segments code need update, please return the full updated segments code, no need import or other stuff, only the full version of the updated segment