I am using the update plotly version 6.3.0 and im trying to plot a simple stock close price in 1year period. The uploaded image is the graph output, how it can be seen its not right. Im also in jupyter notebook, but the other code that i did a long time ago in plotly not graphing either.
import yfinance as yf
import numpy as np
import pandas as pd
import statsmodels.api as sum
from statsmodels.tsa.stattools import coint, adfuller
import plotly.graph_objects as go
petr4 = yf.download("PETR4.SA", period="1y")["Close"]
petr4.index = petr4.index.tz_localize(None)
fig = go.Figure()
fig.add_trace(go.Scatter(x=petr4.index, y=petr4))
fig.update_layout(title_text="petr", width=500, height=500)
fig.show()
Open source code and practices change over time. You have to be ready to troubleshoot now and then.
You'll note the Jan 23, 2025 post 'What’s New in YFinance? 3 Game-Changing Updates You Must Know' starts off saying: "As Heraclitus once said: “The only constant in life is change.”
import yfinance as yf
import numpy as np
import pandas as pd
import statsmodels.api as sum
from statsmodels.tsa.stattools import coint, adfuller
import plotly.graph_objects as go
petr4 = yf.download("PETR4.SA", period="1y", auto_adjust=False)["Close"] #explcitly set `auto_adjust` to avoid `FutureWarning:YF.download() has changed argument auto_adjust default to True`
petr4.index = petr4.index.tz_localize(None)
fig = go.Figure()
fig.add_trace(go.Scatter(x=petr4.index, y=petr4['PETR4.SA']))
fig.update_layout(title_text="petr", width=500, height=500)
fig.show()
To figure out what to, you'd separate things out and run this code to find out what you are dealing with up to the point fig = go.Figure()
:
type(petr4)
Then you'd run this code to get the columns from the Pandas dataframe:
petr4.columns
Then you'd see Index(['PETR4.SA'], dtype='object', name='Ticker')
and try plugging petr4['PETR4.SA']
in as the y-axis data.
Granted that assumes some familiarity with Pandas.
multi_level_index=False
I removed the ["Close"]
you had after the intial petr4
assignment and ran up to the line petr4 = yf.download("PETR4.SA", period="1y")
.
Then in the next Jupyter cell I typed petr4
and ran that and saw a nice dataframe with one of the columns having Close
on top and PETR4.SA
below.
I typed petr4.columns
to investigate further and saw:
MultiIndex([('Adj Close', 'PETR4.SA'),
( 'Close', 'PETR4.SA'),
( 'High', 'PETR4.SA'),
( 'Low', 'PETR4.SA'),
( 'Open', 'PETR4.SA'),
( 'Volume', 'PETR4.SA')],
names=['Price', 'Ticker'])
Seeing 'MultiIndex' I searched on the internet for 'yfinance close multiindex' and saw, "Dec 24, 2024 — Upgraded to yfinance 2.51 this week yf.Download for a single ticker now produces columns with an un-wanted multi-index with an altered ...". That looked pertinent.
That would lead you to ISSUE POST: 'yf.download returns multi-index columns'.
Or if you are lucky, you'll scroll down and see the Jan 23, 2025 post 'What’s New in YFinance? 3 Game-Changing Updates You Must Know' that has in the introductory paragraph:
"YFinance, the popular Python library for retrieving financial data, has introduced significant changes in its latest version 0.2.51 (released in December 2024). These updates have caused confusion among users but also bring interesting functional improvements. In this article, we’ll explore the key updates, how to handle them, and provide practical code examples."
Or in the list of hits, possibly see the Nov 26, 2024 post '[Python] Updates in yfinance: The Multi-Level Index in the “download” Function'.
All those list some options for dealing with this change.
Here is trying one of the ones listed in ISSUE POST: 'yf.download returns multi-index columns'. This reply points out that the API now has an option you can add via an argument to specify you want the old style, & so you could alter your line petr4 = yf.download("PETR4.SA", period="1y")["Close"]
to instead be petr4 = yf.download("PETR4.SA", period="1y",multi_level_index=False)["Close"]
. That implemented in your code block fully would be:
import yfinance as yf
import numpy as np
import pandas as pd
import statsmodels.api as sum
from statsmodels.tsa.stattools import coint, adfuller
import plotly.graph_objects as go
petr4 = yf.download("PETR4.SA", period="1y",multi_level_index=False, auto_adjust=False)["Close"]
petr4.index = petr4.index.tz_localize(None)
fig = go.Figure()
fig.add_trace(go.Scatter(x=petr4.index, y=petr4))
fig.update_layout(title_text="petr", width=500, height=500)
fig.show()
(Note I also added auto_adjust=False
as an argument to avoid FutureWarning:YF.download() has changed argument auto_adjust default to True
I am presently seeing.)
Granted again, I knew about the columns
attribute of Pandas dataframes to even get that far.
Go to StackOverlfow and put in 'yfinance' in the search bar and toggle on 'Newest' as the order for the listing. Then scroll back in recent time and see if anything vaguely looks like your are encountering.
You'd see the post 'Tried plotting yfinance data by framing into pandas with the help of seaborn and matplotlib. Shows error no matter what. How to fix this?' that looks reminiscent of yours and close by this this answer summarized that states:
"Your error was caused by the following code sns.lineplot(x='Date',y='Close',data=df) This is because df is multi-indexed. "
The proposed solution there implemented in your code block:
import yfinance as yf
import numpy as np
import pandas as pd
import statsmodels.api as sum
from statsmodels.tsa.stattools import coint, adfuller
import plotly.graph_objects as go
petr4 = yf.download("PETR4.SA", period="1y").droplevel(1, axis=1)["Close"]
petr4.index = petr4.index.tz_localize(None)
fig = go.Figure()
fig.add_trace(go.Scatter(x=petr4.index, y=petr4))
fig.update_layout(title_text="petr", width=500, height=500)
fig.show()
Even if not clear how to combine the post's suggestion with your code, that statment,'This is because df is multi-indexed' might have lead you to how I got to Solution B because not you may think to search something like 'yfinance close multiindex' on the internet.