Questions - Open Final Exam#

FINM 36700 - 2025#

UChicago Financial Mathematics#


Your Name#

List your name and CNetID

  • Name:

  • CNetID:

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.


Instructions#

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

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

  • 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.

Answer Format#

  • Conceptual answers: Use at most 2 sentences (≈40 words) per conceptual prompt. Graders will only read the first 2 sentences.

  • Output format: When asked for tables, return a small DataFrame with the rows/columns exactly as specified. When asked for a scalar, print it with a clear label.

  • Plots: Plots/figures are not required and will not be graded; focus on numeric outputs and short text.

  • Code organization: You may create additional code cells, but keep your final answers clearly associated with each numbered sub-problem.

  • Numeric answers: Round all reported numbers to 6 decimal places unless noted otherwise.

    • NOTE: The default pandas rounding is 6 decimal places, so if you display a DataFrame, it will likely already be rounded correctly.

Submission#

Type#

  • You should submit a single Jupyter notebook (.ipynb) file containing all of your code and answers to Canvas.

  • Note: If any other files are required to run your notebook, please include them and only them in a single .zip file.

Naming#

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

  • final-LASTNAME-FIRSTNAME.ipynb

  • final-LASTNAME-FIRSTNAME.zip


Scoring#

Problem

Points

1

40

2

45

3

15

Total

Numbered problems are worth 5 points, unless specified otherwise.

Data#

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

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

The exam uses the following data files:

  • quality_factor_final_dataset.csv - stock-level panel data with fundamentals

  • FFF.csv - Fama-French factors (daily)

The stock data contains daily observations from May 2017 to October 2024 with:

  • price - stock price

  • market_cap - market capitalization (in millions)

  • debt_to_market_cap - debt divided by market cap

  • return_on_investment - return on investment (%)

  • price_to_earnings - P/E ratio

The Fama-French data contains:

  • Mkt-RF - market excess return (daily, in percentage points)

  • SMB - small minus big factor

  • HML - high minus low (value) factor

  • RF - risk-free rate

Annualization: Use 252 trading days per year for daily data.


# Load packages
import warnings
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import statsmodels.api as sm
from scipy.stats import norm, skew, kurtosis

warnings.filterwarnings("ignore")
pd.set_option('display.precision', 6)

ANN_FACTOR = 252  # daily data annualization
# Load data
DATA_PATH = 'quality_factor_final_dataset.csv'
FF_PATH = 'FFF.csv'

df = pd.read_csv(DATA_PATH).drop(columns=['Unnamed: 0'])
df['date'] = pd.to_datetime(df['date'])
display(df.tail())

FF = pd.read_csv(FF_PATH).drop(columns=['Unnamed: 0'])
FF['date'] = pd.to_datetime(FF['date'])
FF.set_index('date', inplace=True)
FF = FF / 100  # Convert from percentage points to decimals
display(FF.tail())
date ticker price market_cap debt_to_market_cap return_on_investment price_to_earnings
360179 2024-06-24 ZTS 171.013575 78630.989405 1.280037 5.071555 130.544714
360180 2024-06-25 ZTS 167.172139 76864.720671 1.309451 5.178927 127.612319
360181 2024-06-26 ZTS 170.078095 78200.861786 1.287077 5.097290 129.830607
360182 2024-06-27 ZTS 175.611356 80745.020893 1.246523 4.948753 134.054470
360183 2024-06-28 ZTS 172.526265 79326.514916 1.268814 5.030485 131.699439
Mkt-RF SMB HML RF
date
2024-06-24 -0.0025 0.0062 0.0109 0.00022
2024-06-25 0.0031 -0.0082 -0.0122 0.00022
2024-06-26 0.0016 -0.0001 -0.0019 0.00022
2024-06-27 0.0014 0.0053 -0.0039 0.00022
2024-06-28 -0.0035 0.0100 0.0128 0.00022

1. Quality Factor Construction & Factor Pricing#

In this problem, you will construct a “quality” factor from fundamental data and test its pricing implications using factor models from chapters 4-5.

1.1 Cross-Sectional Z-Scores#

For each date \(t\), compute cross-sectional z-scores for each of the three subfactors:

  • debt_to_market_cap

  • return_on_investment

  • price_to_earnings

The z-score for stock \(i\) on date \(t\) for variable \(x\) is: $\(z_{i,t}^x = \frac{x_{i,t} - \bar{x}_t}{\sigma_t^x}\)$

where \(\bar{x}_t\) and \(\sigma_t^x\) are the cross-sectional mean and standard deviation on date \(t\).

Report the z-scores for ticker AAPL for each subfactor on the last 5 dates in the sample. Round to 6 decimal places.

1.2 Quality Score Construction#

Create a composite quality score by:

  1. Applying economic direction so that “good is high”:

    • debt_to_market_cap → multiply by −1 (lower debt is better)

    • return_on_investment → multiply by +1 (higher ROI is better)

    • price_to_earnings → multiply by −1 (lower P/E is better, i.e., “value”)

  2. Average the three signed z-scores to create quality_raw.

Report quality_raw for ticker AAPL on the last 5 dates. Round to 6 decimal places.

1.3 Size Neutralization#

Quality scores may be correlated with size. To obtain a “pure” quality signal, for each date \(t\), regress quality_raw on the log of market cap:

\[\text{quality\_raw}_{i,t} = \alpha_t + \beta_t \cdot \ln(\text{market\_cap}_{i,t}) + \varepsilon_{i,t}\]

The residual \(\varepsilon_{i,t}\) is the size-neutral quality signal, quality_pure.

Report quality_pure for ticker AAPL on the last 5 dates. Round to 6 decimal places.

1.4 Final Quality Score#

Re-standardize quality_pure cross-sectionally by date to obtain quality_score:

\[\text{quality\_score}_{i,t} = \frac{\text{quality\_pure}_{i,t} - \bar{\text{quality\_pure}}_t}{\sigma_t^{\text{quality\_pure}}}\]

Report quality_score for ticker AAPL on the last 5 dates. Round to 6 decimal places.

1.5. (10pts) Long-Short Factor Portfolio#

Construct a long-short quality factor portfolio:

  1. Compute daily returns for each stock from prices.

  2. Each day, sort stocks into deciles based on quality_pure (using pd.qcut).

  3. Using quality_score as of date t as a signal for return from t to t+1, form portfolios:

    • Long: Equal-weight average return of Decile 10 (highest quality)

    • Short: Equal-weight average return of Decile 1 (lowest quality, “junk”)

    • Factor Return: Long − Short

Report the last 5 daily returns of the Long, Short, and Factor portfolios. Round to 6 decimal places.

1.6 Factor Summary Statistics and Higher Moments#

For the Factor Return (QMJ = Quality Minus Junk), report the following annualized statistics:

  • Mean Return

  • Volatility

  • Sharpe Ratio

Also report the skewness and excess kurtosis of the Factor Return.

1.7.#

In 1–2 sentences, comment on whether the QMJ factor appears to have fatter tails than a normal distribution, based on the higher moments.


2. Forecasting Returns#

In this problem, you will use fundamentals-based signals to forecast returns, following the approach from Chapter 7 (GMO-style forecasting).

Use the QMJ factor return (Factor_Return) constructed in Problem 1.5 for the forecasting analysis below.

2.1 Feature Engineering#

Construct the following predictors for forecasting the quality factor return:

  1. \(X_{\text{Vol}}\) (Fear): Rolling 21-day annualized volatility of Mkt-RF

  2. \(X_{\text{Spread}}\) (Quality Gap): Daily spread in quality scores between Decile 10 and Decile 1: \(\bar{\text{quality\_score}}_{\text{D10},t} - \bar{\text{quality\_score}}_{\text{D1},t}\)

Report the last 5 values for both \(X_{\text{Vol}}\) and \(X_{\text{Spread}}\).

2.2 In-Sample Forecasting Regression#

Estimate the following forecasting regression with predictors lagged one period:

\[r^{\text{QMJ}}_{t+1} = \alpha + \beta_1 X_{\text{Spread},t} + \beta_2 X_{\text{Vol},t} + \epsilon_{t+1}\]

Report:

  • \(R^2\) of the regression

  • Estimated \(\alpha\) (constant)

  • Estimated \(\beta_1\) (X_Spread coefficient)

  • Estimated \(\beta_2\) (X_Vol coefficient)

2.3 Out-of-Sample R²#

Compute out-of-sample (OOS) statistics using a rolling window approach, using the expanding mean (from time 0 to \(t\))as the benchmark/null forecast at time \(t+1\).

Start at \(t =\) 126 (minimum window of 126 days)

2.4 Trading Strategy from Forecasts#

Build a trading strategy using the OOS forecasts:

  1. Set portfolio weight: \(w_t = 10 \times \hat{r}^{\text{QMJ}}_{t+1}\) (scaled forecast)

  2. Strategy return: \(r^{\text{strat}}_{t+1} = w_t \times r^{\text{QMJ}}_{t+1}\)

Report the following annualized statistics for the strategy:

  • Mean Return

  • Volatility

  • Sharpe Ratio

Also report the same annualized statistics for a buy-and-hold position in the QMJ factor.

Round your answers to 6 decimal places.

2.5 Strategy Attribution#

Regress the forecast strategy returns on Mkt-RF:

\[r^{\text{strat}}_{t} = \alpha + \beta \cdot r^{\text{Mkt-RF}}_{t} + \epsilon_t\]

Report:

  • Alpha (annualized)

  • Beta

  • R-squared

  • Annualized Information Ratio

Round your answers to 6 decimal places.

2.6. (10pts) Interpretation for Questions 2.2–2.5#

Answer the following in 1–2 sentences each (total combined length still subject to the global 2-sentence guideline per part):

  1. Is the in-sample \(R^2\) from Question 2.2 meaningful for real-world forecasting? Why or why not?

  2. What does the OOS \(R^2\) from Question 2.3 indicate about the predictability of quality factor returns?

  3. In evaluating the strategy’s performance, do you care more about the OOS \(\alpha\) or the OOS \(R^2\)?

2.7 Strategy Risk#

Compare the tail risk of the Forecast Strategy to the Buy-and-Hold QMJ using the OOS period data:

  1. Compute the Historical VaR (5%) for both strategies

  2. Compute the Maximum Drawdown for both strategies

Report all values. Round to 6 decimal places.

2.8#

In 1–2 sentences, comment on whether the forecast-based strategy has better or worse tail risk than buy-and-hold.


3. Dynamic Hedging & Portable Alpha#

In this problem, you will construct a dynamically hedged quality factor and build a “portable alpha” product, following concepts from Chapters 8-9 (LTCM, managed funds).

3.1 Rolling Factor Regression#

Using a 126-day rolling window**, regress the QMJ factor return on the Fama-French factors:

\[r^{\text{QMJ}}_t = \alpha_t + \beta^{\text{Mkt}}_t \cdot r^{\text{Mkt-RF}}_t + \beta^{\text{SMB}}_t \cdot r^{\text{SMB}}_t + \beta^{\text{HML}}_t \cdot r^{\text{HML}}_t + \epsilon_t\]

Report the rolling betas (Mkt, SMB, HML) for the last 5 dates.

3.2 Hedged Returns#

Construct hedged returns by using the lagged rolling betas as hedge ratios:

\[r^{\text{Hedged}}_t = r^{\text{QMJ}}_t - \left(\hat{\beta}^{\text{Mkt}}_{t-1} \cdot r^{\text{Mkt-RF}}_t + \hat{\beta}^{\text{SMB}}_{t-1} \cdot r^{\text{SMB}}_t + \hat{\beta}^{\text{HML}}_{t-1} \cdot r^{\text{HML}}_t\right)\]

Report the annualized performance statistics (Mean, Volatility, Sharpe) of the hedged return stream.

3.3 Portable Alpha Product#

Construct a portable alpha product that combines:

  1. Levered market exposure: \(r^{\text{LevMkt-RF}}_t = 1.5 \times r^{\text{Mkt-RF}}_t\)

  2. Hedged QMJ overlay: \(r^{\text{Hedged}}_t\)

\[r^{\text{Product}}_t = r^{\text{LevMkt-RF}}_t + r^{\text{Hedged}}_t\]

Regress the product return on the market factor. Report:

  • Beta

  • Alpha (annualized)

Rounded to 6 decimal places.