Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjusted Close from yfinance is not the same as total return from Yahoo Finance #2070

Open
Allen-JThomas opened this issue Oct 3, 2024 · 10 comments

Comments

@Allen-JThomas
Copy link

I am trying to calculate the monthly and annual percent return for a fund like VSMPX. My understanding is that the Adjusted Close from yfinance takes into account splits and dividends.

To get the percent return I am doing:

  hist = ticker.history(start="2020-01-01", end=None, interval="1d", auto_adjust=True)
  # Calculate daily, monthly, and annual percentage returns
  daily_returns = hist['Close'].pct_change()
  monthly_returns = hist['Close'].resample('M').last().pct_change()
  annual_returns = hist['Close'].resample('Y').last().pct_change()
  
  # Save the returns to CSV files
  daily_returns.to_csv("VSMPX_daily_adjusted_returns.csv")
  monthly_returns.to_csv("VSMPX_monthly_adjusted_returns.csv")
  annual_returns.to_csv("VSMPX_annual_adjusted_returns.csv")

My annual return is the following:

2016-12-31 00:00:00-05:00,0.12694628348918013
2017-12-31 00:00:00-05:00,0.21189241900874567
2018-12-31 00:00:00-05:00,-0.05155696029590995
2019-12-31 00:00:00-05:00,0.3079293379439798
2020-12-31 00:00:00-05:00,0.21010764518963132
2021-12-31 00:00:00-05:00,0.2574150697504418
2022-12-31 00:00:00-05:00,-0.19501641528697433
2023-12-31 00:00:00-05:00,0.26013908084513204

However, when I check the total return percentage on the Yahoo Finance website, my adjusted return percentages are off by a little.
image

For example, you can see that my 2019 annual return is 30.79%, but on Yahoo Finance, it is 30.82%. I realize this is a small descripency but I want 1) Understand why there is a difference 2) I noticed every other total return is the same as Yahoo Finance, so concerned I am doing something wrong.

@Kelly-W1115
Copy link

Good question and also wait for an answer

@ValueRaider
Copy link
Collaborator

Hard to answer without Yahoo's source code. Can you get a third opinion from other source e.g. Morning Star?

@vdbergh
Copy link

vdbergh commented Oct 5, 2024

I find it confusing that hist['Close'] actually refers to the adjusted close price and not to the real close price. IMHO yfinance should supply both.

EDIT: I am now seeing that this behavior is configurable through the auto_adjust parameter to history. Sorry for noise!

Incidentally: I tried to compute the adjusted close prices for https://finance.yahoo.com/quote/HYLD.L/history/?period1=1352793600&period2=1728108169 following the explanation here https://help.yahoo.com/kb/SLN28256.html but the numbers I got were also slightly off.

@ValueRaider
Copy link
Collaborator

The adjustment from a dividend is 1.0 - [ dividend / close day before ] . Accumulate them by multiplying. Any differences are rounding errors.

@deeleeramone
Copy link

Total returns typically assumes reinvestment on the payment date, which would create a slightly different value because of the compounding effect.

Instead of discounting the price, the base unit (1 share) increases by the multiplier, base unit * (1 + (div/close)).

The next dividend received, all else equal, would be a slightly larger amount.

The adjusted price level would reflect the increase in the base unit (1 share), not because of any cash flow, but because of compounding from reinvestment.

At the end of the holding period, the exit price would be the closing price multiplied by 1 + however many fractional shares accumulated from reinvestment.

@ValueRaider
Copy link
Collaborator

Instead of discounting the price, the base unit (1 share) increases by the multiplier, base unit * (1 + (div/close)).

Valid way to adjust but Yahoo does reverse.

@Allen-JThomas
Copy link
Author

Allen-JThomas commented Nov 30, 2024

@deeleeramone @ValueRaider Thanks for the answer! Although, I am not quite sure if I follow. Would it be possible to post a code snippet to calculate total return using yfinance?

@jharemza
Copy link

jharemza commented Jan 8, 2025

Calculating Total Return with and without DRIP

Below is an example of how to calculate total returns. First we calculate total returns without dividends reinvested (DRIP) and second we redo the calculation with DRIP "turned on."

Total Return without DRIP

Formula for Total Return without DRIP

The total return over a period (start date to end date) is calculated as:

$$Total\ Return = \frac{\left(Final\ Closing\ Price + Sum\ of\ Dividends\ Received\right)}{Start Closing Price} - 1$$

Where:

  • Final Closing Price = Last market traded price on the end date.
  • Start Closing Price = Last market traded price on the start date.
  • Sum of Dividends Received = Sum of all dividends paid during the period.

Example Code for Total Return without DRIP

import yfinance as yf

# Specify the stock and date range
ticker = 'AAPL'
start_date = '2020-01-01'
end_date = '2023-01-01'

# Fetch historical data
stock_data = yf.Ticker(ticker)
hist = stock_data.history(start=start_date, end=end_date, actions=True)

# Adjusted closing prices
close = hist['Close']

# Dividends
dividends = hist['Dividends']

# Initial and final adjusted prices
initial_price = close.iloc[0]
final_price = close.iloc[-1]

# Total dividends received
total_dividends = dividends.sum()

# Total return calculation
total_return = ((final_price + total_dividends) / initial_price) - 1
print(f"Total Return: {total_return * 100:.2f}%")

Total Return with DRIP

Formula for Total Return with DRIP

To calculate total return with DRIP:

  1. Track how many additional shares are purchased using dividends.
  2. Reinvest dividends at the adjusted closing price on the day the dividend is paid.
  3. Update the total number of shares held over time.
  4. Calculate the final portfolio value using the total shares held and the final adjusted price.

$$Total\ Return \left(DRIP\right) = \frac{Final\ Portfolio\ Value}{Initial\ Portfolio\ Value} - 1$$

Where:

  • Final Portfolio Value = Total shares × Final adjusted price.
  • Initial Portfolio Value = Initial shares × Initial adjusted price.

Example Code for Total Return with DRIP

import yfinance as yf

# Specify the stock and date range
ticker = 'AAPL'
start_date = '2020-01-01'
end_date = '2023-01-01'

# Fetch historical data
stock_data = yf.Ticker(ticker)
hist = stock_data.history(start=start_date, end=end_date, actions=True)

# Start with 1 share
initial_price = hist['Adj Close'].iloc[0]
shares = 1

# Initialize variables
total_shares = shares
for date, dividend in hist['Dividends'].iteritems():
    if dividend > 0:
        # Adjusted closing price on dividend date
        price_on_date = hist.loc[date, 'Adj Close']

        # Calculate additional shares purchased with dividend
        additional_shares = dividend * total_shares / price_on_date

        # Update total shares
        total_shares += additional_shares

# Final adjusted price
final_price = hist['Adj Close'].iloc[-1]

# Final portfolio value
final_portfolio_value = total_shares * final_price

# Initial portfolio value
initial_portfolio_value = shares * initial_price

# Total return with DRIP
total_return_drip = (final_portfolio_value / initial_portfolio_value) - 1
print(f"Total Return with DRIP: {total_return_drip * 100:.2f}%")

@ValueRaider
Copy link
Collaborator

Adding dividends to the adjusted price is total nonsense.

@jharemza
Copy link

jharemza commented Jan 8, 2025

@ValueRaider You are correct. My bad. Adjusted above comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants