4. Introduction to Asset Returns#
🎯 Learning Objectives
By the end of this chapter, you should be able to:
Define and compute total returns
Build returns from price and dividend data, recognizing that “return” is the normalized gain relative to the initial price and works for any positive‐priced asset.Strip out the risk-free rate
Convert raw returns to excess returns so that every subsequent statistic measures compensation over a truly “safe” alternative.Introduce the idea of a risk premium
Understand that the expected value of excess return is the reward for bearing risk, and that estimating it requires a long view of historical dataMotivate the need for a factor model
See why differing betas demand a formal model and set the stage for multi-factor extensions covered in later notebooks.
4.1. What is a return?#
Lets say you paid \(𝑃_𝑡\) in date \(t\) for an asset
In date \(t+1\) the price is \(𝑃_{𝑡+1}\) and you earn some dividend as well \(𝐷_{𝑡+1}\)
Then we say that your return is
It is the gain you made (everything that you go in date t+1), divided by how much you put in ( the price of the asset)
This definition works for ANY asset that has a positive price
This is the case for stocks, bonds, commodities, crypto, most real assets
The return simply normalizes the “dollar gain” by the cost of the asset.
In practice there are many types of distributions that are economically like a dividend but have different names: cash dividends, stock dividends, capital gain distributions, rights offerings, acquisition related distributions, splits
Lets start by loading Price and Dividend data on a single stock
# first we connect with WRDS database using the wrds package so we need to install it first and import it
%pip install wrds
import wrds
# lets connect with the wrds database
conn = wrds.Connection()
WRDS recommends setting up a .pgpass file.
Created .pgpass file successfully.
You can create this file yourself at any time with the create_pgpass_file() function.
Loading library list...
Done
#We now get daily prices and dividends for the UNH stock
# lets not think too hard how we did that--the function is defined above--but for now--lets just used it
df_UNH=get_daily_wrds_single_ticker('UNH',conn)
df_UNH
[92655]
P | D | |
---|---|---|
date | ||
1984-10-18 | 4.87500 | 0.0 |
1984-10-19 | 4.68750 | 0.0 |
1984-10-22 | 4.68750 | 0.0 |
1984-10-23 | 4.56250 | 0.0 |
1984-10-24 | 4.68750 | 0.0 |
... | ... | ... |
2024-12-24 | 506.10001 | 0.0 |
2024-12-26 | 511.14999 | 0.0 |
2024-12-27 | 509.98999 | 0.0 |
2024-12-30 | 507.79999 | 0.0 |
2024-12-31 | 505.85999 | 0.0 |
10131 rows × 2 columns
#How do we construct returns?
# what .shift does?
df_UNH['ret']=?
df_UNH
P | D | ret | |
---|---|---|---|
date | |||
1984-10-18 | 4.87500 | 0.0 | NaN |
1984-10-19 | 4.68750 | 0.0 | -0.038462 |
1984-10-22 | 4.68750 | 0.0 | 0.000000 |
1984-10-23 | 4.56250 | 0.0 | -0.026667 |
1984-10-24 | 4.68750 | 0.0 | 0.027397 |
... | ... | ... | ... |
2023-12-22 | 520.31000 | 0.0 | 0.000827 |
2023-12-26 | 520.03003 | 0.0 | -0.000538 |
2023-12-27 | 522.78998 | 0.0 | 0.005307 |
2023-12-28 | 524.90002 | 0.0 | 0.004036 |
2023-12-29 | 526.46997 | 0.0 | 0.002991 |
9879 rows × 3 columns
df_UNH['ret'].mean()
0.0009104234710832472
If I have invested 100 dollars in a random month in the sample, on average I would have 100.09 in month t+1 in the sample
A return of
Suppose that at the start of the sample we invested 1 dollar in this stock and got all the dividends and used to buy more of the stock,
how many dollars we would have at the end of the sample?
What is the cumulative return on our investment?
What is the annualized return?
What is the dividend yield?
Suppose we are now at the end of the sample
You have 1000 dollars invested in this stock in the end of the sample, the next day there’s a 16% chance your portfolio’s value will fall below a certain amount. How would you estimate that value?
Now suppose you want to know this value in one year? What is your estimate of this value?
What is the expected value of your holdings in one year? How should you think about estimating this?
What can you plot to have a sense of the distribution of 1 day returns? And 1 year returns?
What plot can you to give you a sense of how these returns varying over time?
What drives these returns? Why do they vary over time?
4.2. Decomposing Returns#
Returns of an individual stock can be driven by many things
Time-value of money. There are periods where you can get very high returns even in perfectly safe assets
Common factors, examples: all stocks went up because of a stronger economy, all stocks went down because of a financial crisis
Individual factors impacting the stock: A new drug/a new technology that the firm sells. Anything specific to the firm
When investing is essential to understand where your performance comes from
We will build towards a framework of investing that thinks differently about investing on systematic risk and idiosyncratic risk
The first step will be to build this decomposition, which will start now and culminate in our factor models lecture
4.2.1. Striping the risk-free rate#
In this class we will do a lot of decomposing, but lets start by stripping down the “time-value of money” piece
We first define an “excess return”: the return minus the risk-free rate
We typically use the returns of a 3-month treasury bill to measure the risk-free rate
this obviously should be currency dependent
We will denote \(rf\) for the risk-free rate
We often add superscript “e” to denote an excess return.
so if \(r^i\) stands for the return of stock \(i\), then \(r^{e,i}\) is it’s excess return
Conceptually you want to use the risk-free asset for the relevant holding period you are evaluating the asset returns, but for this class you can think of the “Fed Funds Rate” or the “3-month treasury-bill rate”
from pandas_datareader.data import DataReader
import datetime
# Define the date range
start_date = datetime.datetime(1960, 1, 1) # Start date (adjust as needed)
end_date = datetime.datetime.now() # End date
df_rf = DataReader("DGS3MO", "fred", start_date, end_date)
df_rf.reset_index(inplace=True)
df_rf.columns = ["Date", "rf"]
df_rf.rf=df_rf.rf/100
df_rf.set_index("Date", inplace=True)
df_rf.plot()
<AxesSubplot:xlabel='Date'>

How do we interpret this rate?
Say if I invested in the tbill in 2005 how much money I would have in the end of 3 months? And in the end of the year?
Lets get another stock to play with and merge it together with our risk-free return
df=get_daily_wrds_single_ticker('NVDA',conn,dividends=False)
df=df.merge(df_rf, left_index=True, right_index=True,how='left')
df
[86580]
ret | rf | |
---|---|---|
date | ||
1999-01-25 | 0.104762 | 0.0444 |
1999-01-26 | -0.077586 | 0.0446 |
1999-01-27 | -0.003115 | 0.0447 |
1999-01-28 | -0.003125 | 0.0449 |
1999-01-29 | -0.047022 | 0.0448 |
... | ... | ... |
2024-12-24 | 0.003938 | 0.0440 |
2024-12-26 | -0.002068 | 0.0435 |
2024-12-27 | -0.020868 | 0.0431 |
2024-12-30 | 0.003503 | 0.0437 |
2024-12-31 | -0.023275 | 0.0437 |
6527 rows × 2 columns
Lets construct another column called ‘ret_e’ for excess returns
What is the trading interpretation of such series?
Is it the “return” to which strategy exactly?
How the historical distributions of ret and rete compare?
Are their averages similar?
are their historical standard deviations similar?
Do they have similar interpretation?
Is the standard-deviation of risk-free rate useful to tell you the distribution of you returns in the end of 3 months for an investments in the risk-free asset?