!pip install pandas_ta
!pip install mplfinance

import numpy as np
import pandas as pd
import pandas_ta as ta
import yfinance as yf
import matplotlib.pyplot as plt
import mplfinance as mpf

# Load data file
df = yf.download("^IBEX", start="2023-12-31")

# Drop na
df.dropna(axis=0, how='any', inplace=True)

def calculate_emas(df, window):
    df['Open_EMA'] = df['Open'].ewm(span=window, adjust=False).mean()
    df['Close_EMA'] = df['Close'].ewm(span=window, adjust=False).mean()
    df['High_EMA'] = df['High'].ewm(span=window, adjust=False).mean()
    df['Low_EMA'] = df['Low'].ewm(span=window, adjust=False).mean()
    return df

def bullish_change(df):
    df['bullish_change'] = 0
    for i in range(1, df.shape[0]):
        current = df.iloc[i]
        prev_1 = df.iloc[i - 1]
        idx = df.index[i]
        # Use .item() to get the scalar value from the Series for comparison
        bullish_change = (prev_1['Close'].item() <= prev_1['Open'].item() and 
                          current['Close'].item() > current['Open'].item())  
        if bullish_change:
            df.loc[idx, 'bullish_change'] = 1
    return df

def bearish_change(df):
    df['bearish_change'] = 0
    for i in range(1, df.shape[0]):
        current = df.iloc[i]
        prev_1 = df.iloc[i - 1]
        idx = df.index[i]
        # Use .item() to extract the scalar value and ensure a boolean comparison
        bearish_change = (prev_1['Close'].item() >= prev_1['Open'].item() and 
                          current['Close'].item() < current['Open'].item())  
        if bearish_change:
            df.loc[idx, 'bearish_change'] = 1
    return df

def transform_to_heikin_ashi_smoothed(df):
    ha_df = pd.DataFrame(index=df.index)
    
    # Before calculation, fillna with previous values (ffill method)
    df.ffill(inplace=True)  # Use df.ffill instead of df.fill
    
    ha_df['Close'] = (df['Open_EMA'] + df['High_EMA'] + df['Low_EMA'] + df['Close_EMA']) / 4
    
    ha_df['Open'] = df['Open_EMA']
    for i in range(1, len(ha_df)):
        ha_df.iloc[i, ha_df.columns.get_loc('Open')] = (
            ha_df.iloc[i-1, ha_df.columns.get_loc('Open')] + 
            ha_df.iloc[i-1, ha_df.columns.get_loc('Close')]) / 2
    
    ha_df['High'] = df[['High_EMA', 'Open_EMA', 'Close_EMA']].max(axis=1)
    ha_df['Low'] = df[['Low_EMA', 'Open_EMA', 'Close_EMA']].min(axis=1)
    
    return ha_df

def plot_heikin_ashi_and_changes(df):
    ha_df = df[['Open', 'High', 'Low', 'Close']].copy()
    ha_df = ha_df.apply(pd.to_numeric, errors='coerce')
    ha_df = ha_df.dropna()

    # Create a figure and an axes object outside mpf.plot
    fig, ax1 = plt.subplots(figsize=(15, 8))

    # Plot Heikin Ashi Candlestick Chart on ax1
    # Removed returnfig=True since we already created fig, ax1
    mpf.plot(ha_df, type='candle', style='charles', ax=ax1, 
             title="Heikin Ashi Candlestick Chartdef plot_heikin_ashi_and_changes(df):
    ha_df = df[['Open', 'High', 'Low', 'Close']].copy()
    ha_df = ha_df.apply(pd.to_numeric, errors='coerce')
    ha_df = ha_df.dropna()

    # Create a figure and an axes object outside mpf.plot
    fig, ax1 = plt.subplots(figsize=(15, 8))

    # Plot Heikin Ashi Candlestick Chart on ax1
    # Removed returnfig=True since we already created fig, ax1
    mpf.plot(ha_df, type='candle', style='charles', ax=ax1, 
             title="Heikin Ashi Candlestick Chart and Bullish/Bearish Changes", 
             ylabel='Price', show_nontrading=True)  
    
    # Set the title using ax1.set_title since fig.suptitle won't work with ax
    ax1.set_title("Heikin Ashi Candlestick Chart and Bullish/Bearish Changes")

    # Plot bullish and bearish changes
    bullish_points = df[df['bullish_change'] == 1]
    ax1.plot(bullish_points.index, bullish_points['Close'], 
             'g^', markersize=10, label='Bullish Change')

    bearish_points = df[df['bearish_change'] == 1]
    ax1.plot(bearish_points.index, bearish_points['Close'], 
             'rv', markersize=10, label='Bearish Change')

    ax1.legend()
    plt.show()", 
             ylabel='Price', show_nontrading=True)  
    
    # Set the title using ax1.set_title since fig.suptitle won't work with ax
    ax1.set_title("Heikin Ashi Candlestick Chart and Bullish/Bearish Changes")

    # Plot bullish and bearish changes
    bullish_points = df[df['bullish_change'] == 1]
    ax1.plot(bullish_points.index, bullish_points['Close'], 
             'g^', markersize=10, label='Bullish Change')

    bearish_points = df[df['bearish_change'] == 1]
    ax1.plot(bearish_points.index, bearish_points['Close'], 
             'rv', markersize=10, label='Bearish Change')

    ax1.legend()
    plt.show()

# MAIN
if __name__ == '__main__':
    df = calculate_emas(df, 6)
    df.dropna(inplace=True)
    df = transform_to_heikin_ashi_smoothed(df)
    df = bullish_change(df)
    df = bearish_change(df)
    plot_heikin_ashi_and_changes(df)

I get the error:
AttributeError                            Traceback (most recent call last)
<ipython-input-7-b8faccd20ec4> in <cell line: 31>()
     35     df = bullish_change(df)
     36     df = bearish_change(df)
---> 37     plot_heikin_ashi_and_changes(df)

1 frames
/usr/local/lib/python3.10/dist-packages/mplfinance/plotting.py in plot(data, **kwargs)
    944         else:
    945             title = config['title']      # config['title'] is a string
--> 946         fig.suptitle(title,**title_kwargs)
    947 
    948 

AttributeError: 'NoneType' object has no attribute 'suptitle'