mplfinance icon indicating copy to clipboard operation
mplfinance copied to clipboard

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

Open soshk opened this issue 9 months ago • 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

soshk avatar Mar 05 '25 10:03 soshk

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 #

soshk avatar Mar 05 '25 10:03 soshk