def calculate_risk_factor_attribution(returns, factors, annualization_factor=252):
    """
    Decompose portfolio returns by risk factors using linear regression and provide
    comments on the factor contributions.
    
    Parameters:
    - returns (pd.Series): Portfolio returns.
    - factors (pd.DataFrame): DataFrame where each column represents a risk factor.
                             Must include 'RF' (Risk-Free Rate) if available.
    - annualization_factor (int): Annualization factor (252 for daily, 12 for monthly returns).

    Returns:
    - pd.DataFrame: Factor attribution results
    - str or None: Error message if any issues occur, else None
    """
    try:
        # Ensure returns have a name, or assign one if missing
        if returns.name is None:
            returns = returns.rename("Portfolio_Returns")

        # Convert returns to a DataFrame
        returns = returns.to_frame()

        # Ensure both returns and factors are in decimal format
        if returns['Portfolio_Returns'].abs().max() > 1:
            returns = returns / 100

        if factors.abs().max().max() > 1:
            factors = factors / 100

        # Adjust returns to excess returns by subtracting RF (if it exists in factors)
        if 'RF' in factors.columns:
            returns['Excess_Returns'] = returns['Portfolio_Returns'] - factors['RF']
            factors = factors.drop(columns=['RF'])
        else:
            returns['Excess_Returns'] = returns['Portfolio_Returns']

        # Align the data using an inner join and drop any remaining NaN values
        aligned_data = pd.merge(returns, factors, left_index=True, right_index=True, how='inner').dropna()

        # Check that we have data after merging
        if aligned_data.empty:
            raise ValueError("No overlapping dates between returns and factors after dropping NaNs.")

        # Prepare X and y for regression
        X = aligned_data[factors.columns]
        X = sm.add_constant(X)  # Add intercept
        y = aligned_data['Excess_Returns']

        # Run the regression model
        model = sm.OLS(y, X).fit()
        coefficients = model.params.drop('const', errors='ignore')

        # Calculate factor contributions based on mean returns
        factor_means = X.mean().drop('const', errors='ignore')
        contributions = coefficients * factor_means

        # Calculate total excess return
        total_return = y.mean()

        # Check if total_return is zero to avoid division by zero
        if np.isclose(total_return, 0):
            attribution_df = pd.DataFrame({
                'Factor': contributions.index,
                'Contribution (%)': ["0.00"] * len(contributions)
            })
        else:
            # Calculate percentage contributions
            attribution_df = pd.DataFrame({
                'Factor': contributions.index,
                'Contribution (%)': (contributions / total_return * 100).round(2).astype(str) + "%"
            })

        # Remove the constant term if it exists
        attribution_df = attribution_df[attribution_df['Factor'] != 'const']

        # Replace factor abbreviations with full names
        factor_full_names = {
            'Mkt-RF': 'Market Risk Premium',
            'SMB': 'Small Minus Big',
            'HML': 'High Minus Low',
            'UMD': 'Up Minus Down'
        }
        attribution_df['Factor'] = attribution_df['Factor'].replace(factor_full_names)

        # Generate comments based on factor contributions
        comments = []
        for _, row in attribution_df.iterrows():
            factor_name = row['Factor']
            contribution = float(row['Contribution (%)'].strip('%'))
            
            if factor_name == 'Market Risk Premium':
                if contribution > 75:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Extremely high sensitivity to market movements.")
                elif contribution > 50:
                    comments.append(f"{factor_name} = {contribution:.2f}%: High sensitivity to overall market movements.")
                elif contribution > 30:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Notable sensitivity to market risk.")
                elif contribution > 10:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Moderate exposure to market risk.")
                else:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Low exposure to market risk.")
            
            elif factor_name == 'Small Minus Big':
                if contribution > 5:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Strong tilt towards small-cap stocks.")
                elif contribution > 0:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Mild preference for small-cap stocks.")
                elif contribution > -5:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Slight tilt towards larger-cap stocks.")
                else:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Clear preference for large-cap stocks.")
            
            elif factor_name == 'High Minus Low':
                if contribution > 5:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Strong tilt toward value stocks.")
                elif contribution > 0:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Slight positive tilt toward value stocks.")
                elif contribution > -5:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Minor negative tilt toward growth stocks.")
                else:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Clear preference for growth stocks.")
            
            else:
                if contribution > 0:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Positive contribution to portfolio returns.")
                elif contribution < 0:
                    comments.append(f"{factor_name} = {contribution:.2f}%: Negative contribution to portfolio returns.")
                else:
                    comments.append(f"{factor_name} = {contribution:.2f}%: No significant contribution.")

        # Add comments to the DataFrame
        attribution_df['Comment'] = comments

        return attribution_df, None

    except Exception as e:
        error_message = f"Error calculating risk factor attribution: {e}"
        return pd.DataFrame(), error_message

SyntaxError: File "/www/wwwroot/portfolio_optimizer/metrics.py", line 425 def calculate_risk_factor_attribution(returns, factors, annualization_factor=252): ^ SyntaxError: expected 'except' or 'finally' block
Traceback:
File "/www/server/pyporject_evn/portfolio_optimizer_venv/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/exec_code.py", line 88, in exec_func_with_error_handling
    result = func()
             ^^^^^^
File "/www/server/pyporject_evn/portfolio_optimizer_venv/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 579, in code_to_exec
    exec(code, module.__dict__)
File "/www/wwwroot/portfolio_optimizer/pages/2_Run_Backtest.py", line 3, in <module>
    from components.run_backtest import run_backtest_ui
File "/www/wwwroot/portfolio_optimizer/components/run_backtest.py", line 17, in <module>
    from metrics import (

fix it