Open Midterm 1#

FINM 36700 - 2025#

UChicago Financial Mathematics#


Instructions#

Please note the following:#

Points

  • For every minute late you submit the exam, you will lose one point.

Rules

  • The exam is open-material, closed-communication.

Advice

  • If you find any question to be unclear, state your interpretation and proceed. We will only answer questions of interpretation if there is a typo, error, etc.

Data#

All data files are found in at the course web-book.

https://markhendricks.github.io/finm-portfolio/.

Scoring#

Problem

Points

1

70

2

30

Numbered problems are worth 5pts unless specified otherwise.


Submitting your Exam#

Your submitted file (ipynb or .zip) must be named in the format…

  • midterm-1-LASTNAME-FIRSTNAME.ipynb

  • midterm-1-LASTNAME-FIRSTNAME.zip

Submit the exam via

Your submission must be complete.

  • If we can’t run the notebook to reproduce, it is not complete.

You should either…

  • include all helper functions at the top of this notebook in the Solution Functions sections.

  • submit a zipped folder containing the solution functions

Exam Submission Structure:

If you are submitting a zipped folder (because you cannot make the ipynb stand-alone) then use this structure…

exam-open-LASTNAME-FIRSTNAME.zip/
│── exam-open.ipynb
│── data/
│   ├── example_data.csv
│── modules/
│   ├── my_functions.py

Your Functions#

Please put all functions needed to run the ipynb here.

  • We must be able to run the notebook!

  • If you can’t get all the functions into this ipynb, then make sure to zip your ipynb and supporting materials and submit the zipped folder.

  • But most of you should be able to submit a single, stand-alone ipynb.


Citations#

AI#

List any AI tools used in the exam. No need to list prompts, but rather just AI models or IDE integrations.

I expect most students will have something to list here.

Other resources#

Please list any other resources aside from course materials from which you used substantially. (No need to list every Google search; just materials from which you used substantially or for specific, original content.)

I expect most students will not have anything to list here.


Your Name#

List your name and CNetID

  • Name:

  • CNetID:


1. Portfolio Analysis#

Data#

Use the data in data/midterm_1_stock_returns.xlsx.

The returns are…

  • excess returns

  • weekly

  • through May 2025

It has returns for

  • 25 single-name equities

  • SPY

import pandas as pd

DATAFILE_STOCKS = '../data/midterm_1_stock_returns.xlsx'

SHEET = 'stock rets'
rets = pd.read_excel(DATAFILE_STOCKS, sheet_name=SHEET, index_col='date', parse_dates=['date'])

SHEET = 'benchmark rets'
spy = pd.read_excel(DATAFILE_STOCKS, sheet_name=SHEET, index_col='date', parse_dates=['date'])

display(rets.head())
display(spy.tail())
ADSK AOS BKNG CBRE CCI CF CHRW DE DGX DTE ... MRK MTD PG PNR SBAC STE TTWO VTRS WM WMT
date
2015-01-09 -0.021166 -0.008927 -0.078893 -0.000577 0.026536 0.069378 -0.024107 -0.030450 -0.003635 -0.002414 ... 0.093897 -0.008843 -0.002101 -0.023393 -0.001091 0.013659 -0.008009 -0.009050 -0.004251 0.040160
2015-01-16 -0.024369 -0.015313 -0.041579 -0.045022 0.012374 0.001515 0.019290 0.019265 0.019738 0.036405 ... 0.007512 -0.024325 0.011081 -0.009830 -0.012042 -0.020590 0.048080 0.002865 0.013778 -0.028873
2015-01-23 0.023571 0.016282 0.029527 -0.004231 0.050829 0.013841 0.009121 0.012027 0.016490 0.014229 ... -0.008567 0.037842 -0.005804 -0.003565 0.080951 0.023033 0.022253 -0.031965 0.014548 0.020053
2015-01-30 -0.071920 0.069487 -0.027466 -0.018513 -0.003684 0.012031 -0.039124 -0.035766 0.002540 -0.017317 ... -0.035366 0.002970 -0.064277 -0.033041 -0.014190 -0.014506 -0.004689 -0.019552 -0.029622 -0.039883
2015-02-06 0.056754 0.037577 0.012818 0.048856 0.001733 -0.028619 -0.009970 0.044489 -0.020120 -0.049186 ... -0.024717 0.016318 0.015660 0.040609 0.010108 0.026985 -0.031460 0.013922 0.019639 0.027653

5 rows × 25 columns

SPY
date
2025-04-25 0.046029
2025-05-02 0.029275
2025-05-09 -0.004270
2025-05-16 0.052911
2025-05-23 -0.025395

1 Performance Stats#

1.1. Calculate the Sharpe ratio for each stock during the sample period#

  • Recall: the sample period ranges from January 2015 to December 2024 (inclusive).

  • Report the top 5 stocks with the highest Sharpe ratios.

1.2. Display the correlation matrix for the first ten stocks (columns) over the sample period.#

  • On average, are these stocks highly correlated? Explain.

  • Which of these stocks offer the best diversification benefits?

2. In-Sample Tangency (excess returns)#

Note#

Consider in-sample to be all the data through the end of 2024.

2.1. Construct the tangency portfolio#

Using just the in-sample data (through 2024), calculate the tangency portfolio weights, assuming we have excess returns (existence of a risk-free rate.)

  • Display the ten largest portfolio weights.

  • Plot the Sharpe ratios against the portfolio weights.

2.2.#

Compare the relationship between tangency portfolio weights and individual sharpe ratios.

2.3. Performance of the Tangency#

Continue with the in-sample tangency portfolio constructed above, and analyze how it performs in-sample (through 2024.)

Report the (annualized)

  • mean

  • volatility

  • Sharpe ratio

  • skewness (not annualized)

Plot the cumulative return of the tangency portfolio over the sample period.

3. Hedging the Tangency Portfolio#

Continue with the in-sample (through 2024) tangency returns calculated in the previous problem.

3.1.#

Compute portfolio returns and regress on SPY to get \(\hat{\beta}\).

Include an intercept in the regression.

Report \(\hat{\beta}\).

3.2.#

Calculate the returns to the hedged position.

Report the (annualized)

  • mean

  • volatility

  • Sharpe ratio

  • skewness (not annualized)

4. Out-of-Sample#

4.1. Tangency Portfolio Performance: Out-of-Sample (OOS)#

Use the weights of the tangency portfolio calculated above.

Compute the out-of-sample returns (2025), and just for this OOS portion, report the (annualized)

  • mean

  • volatility

  • Sharpe ratio

  • skewness (not annualized)

4.2. Cumulative performance#

  • Include the OOS performance in the cumulative return plot (in addition to the in-sample performance).

Show the plot.

5. Optimizing Hedged Returns#

5.1. Construct Market-Hedged Returns#

Active managers might optimize their portfolios using market-hedged returns to focus on alpha generation (maximize portion of returns orthogonal to the market). Market-hedged returns are the residuals from regressing each stock’s excess return on the market’s excess return (e.g., SPY), effectively removing market beta to isolate stock-specific (idiosyncratic) performance.

  • Regress each stock’s excess return on the SPY index (quoted in excess return) over the sample period.

  • Include an intercept.

  • Report your betas.

5.2. The residuals#

Save the residuals from each regression as the market-hedged returns.

Report the .tail() (last 5 observations) of the residual dataframe.

5.3 Diversification Benefits of Market-Hedged Returns#

Display the covariance matrix of the market-hedged returns for the first ten stocks.

5.4. Portfolio Optimization with Market-Hedged Returns#

Construct the tangency portfolio using the alphas (intercept from previous regression) as expected returns and the covariance matrix of the market-hedged returns. Display the portfolio weights.

5.5. Performance of the Tangency of the Hedged#

Calculate the returns to the portfolio with weights from the previous question (just in-sample).

Report the (annualized)

  • mean

  • volatility

  • Sharpe ratio

  • skewness (not annualized)


2. Managing Risk#

DATAFILE = '../data/midterm_1_fund_returns.xlsx'
df = pd.read_excel(DATAFILE, sheet_name='fund returns').set_index('date')
df
fund
date
2015-01-09 0.003444
2015-01-16 -0.000959
2015-01-23 0.004491
2015-01-30 0.010560
2015-02-06 -0.001624
... ...
2024-11-29 0.013893
2024-12-06 -0.027113
2024-12-13 0.002755
2024-12-20 0.020840
2024-12-27 -0.046301

521 rows × 1 columns

1. Calculating Volatility#

Given the return data provided, calculate the annual volatility grouped by year. Annualize this volatility. That is, your answer should be a DataFrame with 10 rows (one for each year from 2015 to 2024) and a single column representing the annualized volatility for that year.

What do you notice about the volatility across different years?

2. Volatility Estimates#

Using the return data, compute the annualized volatility estimate as of the last data point using the following methods:

  • EWMA volatility with a half-life of 26 weeks.

  • Rolling window volatility with a window size of 52 weeks.

Note: do not specify a “min_periods” argument anywhere.

3. Dynamic VaR estimates#

Using the return data, compute the 1-week 1% VaR as of the last data point in the series.

You should use two different volatility models to compute the VaR:

  • EWMA volatility with a half-life of 26 weeks.

  • Rolling-window volatility with a window of 52 weeks.

  • Empirical (expanding) VaR.

4. Dynamic CVaR estimates#

Repeat Question 3, but instead compute the 1-week 1% Conditional VaR (CVaR) as of the last data point in the series using the same three methods.

5. Year Choice#

Suppose instead we were interested in our VaR estimates as of the end of 2023 (ie. use all data that is before 2024-01-01). Report your VaR (1-week, 1%) estimates using the same three methods as in Question 3, but now the last data point in 2023.

Hint: You can use df.loc[:'2023'] to filter the DataFrame to only include data up to the end of 2023.

6. Compare#

What do you notice about the VaR estimates compared to those from question 2.3?