matplotlib/mplfinance

how to show more area at the far right side of the Ichimoku Cloud Chart

Opened this issue · 1 comments

Greeting!
I am a newbie in Python, and I greatly appreciate this brilliantly made built-in package for visualization of yfinance data.
I am learning and trying to plot the Ichimoku Cloud Chart, and found that the plot displayed would show with the x-axis limited at the latest data date, while the Ichimoku indicator actually would plot the cloud area 26days into future.

I tried to extend the x-axis using the xlim() function to extend 1 month into future, but the cloud still is not shown in the plot.

I have checked and make sure that in my calculations, the shift() function is applied to the calculation of the 3 lines, Leading Span A, Leading Span B, and Lagging Span. Thus I believe that there would be data to be plotted for the future date.

The first chart below is the plot generated from my broken code.
And the lower chart is a chart I got from a free online platform. I target to make my plot look more or less like this.
May I get help on how I can correctly plot the cloud for the Ichimoku chart?

Thanks in advance.

This is the chart plotted from my broken python code
Image

This is the chart I got from a free online platform. I target to make my plot look more or less like this.
Image

in case it is necessart, this is my broken code

# This allows multiple outputs from a single jupyter notebook cell:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

import yfinance as yf
import pandas as pd
import mplfinance as mpf
import numpy as np
import datetime as dt
from datetime import timedelta, date

# for fixing 
# Error: Cannot compare tz-naive and tz-aware datetime-like objects
import pytz
from dateutil.relativedelta import relativedelta

# Print mplfinance version for debugging
#print(f"mplfinance version: {mpf.__version__}")

def get_stock_data(stock_symbol, start, end):
    # Fetch stock data
    security = yf.Ticker(stock_symbol)
    stock = security.history(interval='1d', start=start_date, end=end_date)
    #stock = yf.download(stock_symbol, start=start_date, end=end_date)
        
    if stock.empty:
        raise ValueError(f"No data retrieved for symbol '{stock_symbol}' between {start_date} and {end_date}")
    
    # Calculate Ichimoku components, default parameters = 9, 26, 52
    # Tenkan-sen (Conversion Line): (9-period high + 9-period low)/2
    high_9 = stock['High'].rolling(window=9).max()
    low_9 = stock['Low'].rolling(window=9).min()
    stock['Tenkan_sen'] = (high_9 + low_9) / 2
    
    # Kijun-sen (Base Line): (26-period high + 26-period low)/2
    high_26 = stock['High'].rolling(window=26).max()
    low_26 = stock['Low'].rolling(window=26).min()
    stock['Kijun_sen'] = (high_26 + low_26) / 2
    
    # Senkou Span A (Leading Span A): (Conversion Line + Base Line)/2 shifted 26 periods forward
    stock['Senkou_Span_A'] = ((stock['Tenkan_sen'] + stock['Kijun_sen']) / 2).shift(26)
    
    # Senkou Span B (Leading Span B): (52-period high + 52-period low)/2 shifted 26 periods forward
    high_52 = stock['High'].rolling(window=52).max()
    low_52 = stock['Low'].rolling(window=52).min()
    stock['Senkou_Span_B'] = ((high_52 + low_52) / 2).shift(26)
    
    # Chikou Span (Lagging Span): Close price shifted 26 periods back
    stock['Chikou_Span'] = stock['Close'].shift(-26)
    
    # Calculate MACD, default parameter = 12, 26, 9
    stock['EMA_12'] = stock['Close'].ewm(span=12, adjust=False).mean()
    stock['EMA_26'] = stock['Close'].ewm(span=26, adjust=False).mean()
    stock['MACD'] = stock['EMA_12'] - stock['EMA_26']
    stock['Signal_Line'] = stock['MACD'].ewm(span=9, adjust=False).mean()
    stock['MACD_Hist'] = stock['MACD'] - stock['Signal_Line']
    
    # Calculate RSI, default 14days RSI vs 5days SMA
    delta = stock['Close'].diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
    rs = gain / loss
    stock['RSI'] = 100 - (100 / (1 + rs))
    
    
    return stock

def plot_ichimoku_with_indicators(stock_symbol, data):
    # Prepare the data for mplfinance (OHLC format)
    ohlc_data = data[['Open', 'High', 'Low', 'Close', 'Volume']].copy()
    
    # Debugging
    print("ohlc_data head:\n", ohlc_data.head())
    print("ohlc_data columns:", ohlc_data.columns.tolist())
    print("Volume NaN count in ohlc_data:", ohlc_data['Volume'].isna().sum())
    
    # Define additional plots for Ichimoku lines
    ichimoku_lines = [
        mpf.make_addplot(data['Tenkan_sen'], color='red', label='Tenkan-sen'),
        mpf.make_addplot(data['Kijun_sen'], color='blue', label='Kijun-sen'),
        mpf.make_addplot(data['Senkou_Span_A'], color='yellow', label='Senkou_Span_A'),
        mpf.make_addplot(data['Senkou_Span_B'], color='purple', label='Senkou_Span_B'),        
        mpf.make_addplot(data['Chikou_Span'], color='black', label='Chikou Span'),        
    ]
    
    # Define the fill_between Senkou_Span_A and Senkou_Span_B for the cloud directly in the plot call
    cloud_fill = [dict(y1=data['Senkou_Span_A'].values, y2=data['Senkou_Span_B'].values, where=data['Senkou_Span_A'] >= data['Senkou_Span_B'], alpha=0.3, color='green'),
                    dict(y1=data['Senkou_Span_A'].values, y2=data['Senkou_Span_B'].values, where=data['Senkou_Span_A'] < data['Senkou_Span_B'], alpha=0.3, color='red')]
    
    # Volume = True in mpf.plot(), being panel = 1
    
    # Define MACD panel
    macd_plots = [
        mpf.make_addplot(data['MACD'], color='blue', label='MACD', ylabel='MACD', y_on_right=False, panel=2, title="MACD"),
        mpf.make_addplot(data['Signal_Line'], color='orange', label='Signal Line', panel=2),
        mpf.make_addplot(data['MACD_Hist'], type='bar', color='gray', alpha=0.5, label='Histogram', panel=2),
        mpf.make_addplot(pd.Series(0, index=data.index), color='black', linestyle='--', panel=2, width=0.5)
    ]
    
    # Define RSI panel
    rsi_plots = [
        mpf.make_addplot(data['RSI'], color='blue', label='RSI', ylabel='RSI', y_on_right=False, panel=3, title="RSI"),
        mpf.make_addplot(pd.Series(70, index=data.index), color='red', linestyle='--', panel=3, width=0.5),
        mpf.make_addplot(pd.Series(30, index=data.index), color='green', linestyle='--', panel=3, width=0.5)
    ]

    all_plots = ichimoku_lines + macd_plots + rsi_plots
        
    # Plot using mplfinance
    mpf.plot(ohlc_data,
             type='hollow_candle',  # Use candlestick chart, hollow
             style='yahoo',  # Yahoo-style coloring
             title=f'Ichimoku Cloud Chart - {stock_symbol}',
             addplot=all_plots,
             volume=True,   # panel = 1
             panel_ratios=(3, 1, 1, 1),  # Adjust panel sizes
             fill_between=cloud_fill, # Add cloud fill for Ichimoku
             ylabel='Price',
             ylabel_lower='Volume',
             #y_on_right=False,
             xlim=(start_date, xlim_end),
             figscale=1.5,
             tight_layout=True,
    )

# Example usage
if __name__ == "__main__":
    #Set parameters
    #ask suer for stock symbol
    stock_symbol = input("Please enter the stock symbol: ")
    start_date = dt.datetime(date.today().year - 1, date.today().month, date.today().day, tzinfo=pytz.UTC)
    end_date = dt.datetime(date.today().year, date.today().month, date.today().day, tzinfo=pytz.UTC)
    xlim_end = dt.datetime.today().replace(tzinfo=pytz.UTC) + relativedelta(months=1)

    # Get data and plot
    try:
        ichimoku_data = get_stock_data(stock_symbol, start_date, end_date)
        if ichimoku_data.empty:
            raise ValueError("No data returned for the specified stock symbol.")
        plot_ichimoku_with_indicators(stock_symbol, ichimoku_data)
    except Exception as e:
        print(f"Error: {str(e)}")

# Requirements:
# pip install yfinance pandas mplfinance numpy #