← Back to BRISMA Wiki

Julian's Calibration Methods

A Complete Tutorial on Market Implied Returns from Factor Models

Author: Julian Lorenz (Bantleon) | Level: Intermediate to Advanced | Prerequisites: Linear algebra, basic statistics, factor models

1. Introduction: The Expected Return Problem

Learning Objectives

  • Understand why expected returns are difficult to estimate
  • Learn how factor models provide a framework for expected return estimation
  • Appreciate the difference between forward-looking and backward-looking approaches

1.1 The Challenge

In portfolio optimization, we need three key inputs:

  1. Expected returns \(\bm{\mu}\) - what we expect each asset to return
  2. Covariance matrix \(\bm{Q}\) - how assets move together
  3. Constraints - limits on positions, turnover, etc.

While covariance matrices can be estimated reliably from historical data (they're relatively stable), expected returns are notoriously difficult to estimate. Small errors in expected returns lead to large errors in optimal portfolios.

The Core Problem

Historical average returns are poor predictors of future returns. A 10-year sample gives us maybe 10 independent annual observations - far too few to estimate expected returns with any precision.

Standard error of mean return estimate: \(\frac{\sigma}{\sqrt{T}} \approx \frac{16\%}{\sqrt{10}} = 5\%\)

This means our confidence interval for equity expected returns might be [-2%, +12%] - essentially useless for portfolio construction!

1.2 Julian's Solution: Factor-Based Calibration

Julian Lorenz developed two practical methods that leverage the BRISMA factor model to derive expected returns. The key insight is:

Central Idea

If asset returns are driven by common factors, then expected returns should also be driven by those factors.

\[\mu_i = \beta_{i,1} \cdot \lambda_1 + \beta_{i,2} \cdot \lambda_2 + \ldots\]

The two methods differ in how they estimate the factor premiums \(\lambda_k\):

Method 1: 10Y Bond Calibration

Approach: Use the current 10-year German Bund yield to back out the factor premium.

Philosophy: Market prices contain forward-looking information.

Type: Forward-looking

Method 2: Historical Performance

Approach: Use time-weighted historical factor returns.

Philosophy: Past performance contains information about future returns (momentum).

Type: Backward-looking

2. Factor Model Foundations

Learning Objectives

  • Understand the single-factor and multi-factor return models
  • Derive the expected return formula from no-arbitrage conditions
  • Connect factor betas to expected returns

2.1 The Factor Model for Returns

A factor model decomposes asset returns into systematic and idiosyncratic components:

Single-Factor Model
\[r_i = \alpha_i + \beta_{i,1} \cdot f_1 + \epsilon_i\]

Where:

2.2 From Returns to Expected Returns

Taking expectations on both sides:

\[\E[r_i] = \alpha_i + \beta_{i,1} \cdot \E[f_1] + \E[\epsilon_i]\]

Since \(\E[\epsilon_i] = 0\):

\[\mu_i = \alpha_i + \beta_{i,1} \cdot \mu_{f_1}\]

The No-Arbitrage Condition

In equilibrium, there should be no "free lunch." If an asset has no systematic risk (\(\beta = 0\)), it shouldn't earn more than the risk-free rate. This implies:

\[\alpha_i = 0 \quad \text{for all assets}\]

Therefore:

\[\boxed{\mu_i = \beta_{i,1} \cdot \lambda}\]

where \(\lambda = \E[f_1]\) is the factor risk premium.

2.3 Interpretation

The formula \(\mu_i = \beta_{i,1} \cdot \lambda\) has a beautiful interpretation:

TermMeaningUnits
\(\beta_{i,1}\)Quantity of Factor 1 risk in asset \(i\)Dimensionless
\(\lambda\)Price per unit of Factor 1 risk% per year
\(\mu_i\)Total compensation for bearing Factor 1 risk% per year

Example

If the factor premium is \(\lambda = 2\%\) per year:

  • An asset with \(\beta = 1.0\) has expected return = \(1.0 \times 2\% = 2\%\)
  • An asset with \(\beta = 0.5\) has expected return = \(0.5 \times 2\% = 1\%\)
  • An asset with \(\beta = 2.0\) has expected return = \(2.0 \times 2\% = 4\%\)

2.4 The Calibration Problem

We have the betas \(\beta_{i,1}\) from the factor model estimation (PCA on the covariance matrix). What we don't have is the factor premium \(\lambda\).

Julian's key insight: We can back out \(\lambda\) from a reference asset where we have a reasonable estimate of expected return!

3. Method 1: 10-Year Bond Calibration

Learning Objectives

  • Learn how to calibrate the factor premium from bond yields
  • Project expected returns to all assets using factor betas
  • Understand when this method is reliable

3.1 The Key Assumption

Method 1 Assumption

For a buy-and-hold investor, the yield-to-maturity of a bond approximates its expected return.

Specifically, for the 10-year German Bund:

\[\E[r_{10Y}] \approx y_{10Y} - r_f\]

where \(y_{10Y}\) is the 10-year yield and \(r_f\) is the overnight rate (ESTR).

This assumption is reasonable because:

3.2 Step-by-Step Procedure

Calculate Target Bond Return

Compute the expected excess return of the 10-year bond:

\[r_{target} = \ln\left(\frac{1 + y_{10Y}}{1 + r_f}\right)\]

Example: With \(y_{10Y} = 2.8\%\) and \(r_f = 2.4\%\):

\[r_{target} = \ln\left(\frac{1.028}{1.024}\right) = +0.39\%\]

Back Out Lambda

Using the factor model equation for the reference bond:

\[\mu_{bond} = \beta_{bond,1} \cdot \lambda\]

Solving for \(\lambda\):

\[\lambda = \frac{r_{target}}{\beta_{bond,1}}\]

Example: With \(\beta_{bond,1} = 0.95\):

\[\lambda = \frac{0.39\%}{0.95} = 0.41\%\]

Project to All Assets

Apply the factor model to every asset in the portfolio:

\[\mu_i = \beta_{i,1} \cdot \lambda\]

Example:

  • Bond: \(\mu = 0.95 \times 0.41\% = 0.39\%\) (matches target - sanity check!)
  • Equity (\(\beta = 0.25\)): \(\mu = 0.25 \times 0.41\% = 0.10\%\)

3.3 Julian's Original R Code

# Step 1: Define target return from yield curve
yield_10y <- 0.028      # 10-year German Bund yield
estr_rate <- 0.024      # ESTR overnight rate
return_asset_10year <- log((1 + yield_10y) / (1 + estr_rate))  # ~0.39%

# Step 2: Back out lambda using reference bond's beta
# Julian's comment: "The factor-risk-premium lambda_ is not estimated
# but rather calibrated based on the 10-year-rate"
lambda_ <- return_asset_10year / beta_id_id_comp.fit["comp1", reference_bond_id]

# Step 3: Project to all assets
# Julian's comment: "For all the assets of the model the expected
# excess returns are computed via the given betas"
mu_implied <- as.vector(t(beta_id_id_comp.fit["comp1", ]) * lambda_)

When Method 1 May Fail

  • Inverted yield curve: Negative excess return implies negative \(\lambda\)
  • Low R-squared assets: Factor model doesn't explain their returns
  • Credit-sensitive bonds: Yield includes credit spread, not just rate expectations

4. Method 2: Historical Performance

Learning Objectives

  • Learn how to estimate factor premiums from historical data
  • Understand time-weighted averaging
  • Recognize the momentum philosophy behind this approach

4.1 The Key Assumption

Method 2 Assumption

Past factor performance contains information about future factor returns.

This is related to the momentum effect: assets that performed well recently tend to continue performing well.

4.2 Step-by-Step Procedure

Compute Factor Returns

The factor returns are the principal component returns from the BRISMA model. These are already computed during covariance estimation.

Apply Time Weights

Recent returns get higher weight (exponential decay):

\[w_t = \frac{(1-\delta)^{T-t}}{\sum_{s=1}^{T}(1-\delta)^{T-s}}\]

where \(\delta\) is the decay rate (same as used for covariance estimation).

Compute Weighted Average Factor Return

\[\hat{\mu}_{f_1} = \sum_{t=1}^{T} w_t \cdot r_{f_1,t}\]

Then annualize appropriately.

Project to All Assets

Same formula as Method 1:

\[\mu_i = \beta_{i,1} \cdot \hat{\mu}_{f_1}\]

4.3 Julian's Original R Code

# Step 1-2: Compute weighted factor returns
# Julian uses the same weights as covariance estimation

# Rolling returns of principal components
ret_roll_rm_comp <- ret22_date_id_rm %*% ei_port$vectors

# Time and GARCH weights (already computed in covariance estimation)
weighted_returns <- weight_time_garch * ret_roll_rm_comp

# Step 3: Sum weighted returns (annualized)
# Julian's comment: "The comp1_return_weighted represents the weighted
# historical returns of comp1"
comp1_return_weighted <- sum(weighted_returns[, 1]) * annualization_factor

# Step 4: Project to assets via betas
mu_from_past <- as.vector(t(beta_id_id_comp.fit["comp1", ]) * comp1_return_weighted)

4.4 Why Time-Weighting?

The time-weighted average has several advantages:

AdvantageExplanation
Regime sensitivity Adapts to changing market conditions
Consistency Same weights as covariance estimation (coherent model)
Momentum capture Recent performance weighted more heavily
GARCH integration High-volatility periods get appropriate weight

5. The R-Squared Quality Check

Learning Objectives

  • Understand what R-squared measures in this context
  • Calculate R-squared for each asset
  • Use R-squared to assess reliability of implied returns

5.1 The Problem of Low Factor Exposure

Both methods project expected returns using:

\[\mu_i = \beta_{i,1} \cdot \lambda\]

But what if Factor 1 explains very little of asset \(i\)'s variance? Then the projected expected return is essentially meaningless!

R-Squared as Quality Metric

R-squared measures what fraction of an asset's variance is explained by Factor 1:

\[R^2_i = \frac{\beta_{i,1}^2 \cdot \sigma^2_{f_1}}{\sigma^2_i} = \frac{\text{Systematic Variance}}{\text{Total Variance}}\]

5.2 Derivation

From the factor model:

\[r_i = \beta_{i,1} \cdot f_1 + \epsilon_i\]

Taking variance:

\[\Var(r_i) = \beta_{i,1}^2 \cdot \Var(f_1) + \Var(\epsilon_i)\] \[\sigma^2_i = \beta_{i,1}^2 \cdot \sigma^2_{f_1} + \sigma^2_{\epsilon,i}\]

R-squared is the fraction explained by the factor:

\[R^2_i = \frac{\beta_{i,1}^2 \cdot \sigma^2_{f_1}}{\sigma^2_i}\]

5.3 Interpretation Table

R-squaredInterpretationRecommendation
> 80% Factor dominates asset risk High confidence in \(\mu_i = \beta_i \lambda\)
50% - 80% Mixed systematic/idiosyncratic Use with caution; consider blending
< 50% Idiosyncratic risk dominates Factor-based return unreliable; use alternatives

5.4 Example Calculation

Example: Bond vs Equity

Given:

  • Bond: \(\sigma = 4\%\), \(\beta = 0.95\)
  • Equity: \(\sigma = 16\%\), \(\beta = 0.25\)
  • Factor 1: \(\sigma_{f_1} = 4\%\)

Bond R-squared:

\[R^2_{bond} = \frac{0.95^2 \times 0.04^2}{0.04^2} = 0.95^2 = 0.90 \quad (90\%)\]

Equity R-squared:

\[R^2_{equity} = \frac{0.25^2 \times 0.04^2}{0.16^2} = \frac{0.0001}{0.0256} = 0.004 \quad (0.4\%)\]

Conclusion: Factor-based expected returns are reliable for bonds, but essentially meaningless for equities!

5.5 Julian's R Code for R-Squared

# Julian's comment: "The explained variance R^2 per asset comes with the idea
# that the market implied return coming from our model should only be
# considered to be reliable for those assets where R^2 is high"

# Calculate R-squared for each asset
var_factor1 <- var(factor_returns[, 1])
var_assets <- diag(Q_emp)  # Empirical variances

R_squared <- (beta_comp1^2 * var_factor1) / var_assets

# Create reliability table
tbl_mir <- tibble(
  asset = asset_names,
  mu_implied = mu_implied,
  R_squared = R_squared,
  reliable = R_squared > 0.50
)

6. Comparing the Methods

Learning Objectives

  • Understand when to use each method
  • Recognize the trade-offs between forward and backward-looking approaches
  • Learn how to combine the methods

6.1 Side-by-Side Comparison

AspectMethod 1: 10Y BondMethod 2: Historical
Data Source Current yield curve Historical returns
Philosophy Market expectations matter Momentum persists
Time Orientation Forward-looking Backward-looking
Anchor Observable market rate Historical average
Best for Fixed-income portfolios Trend-following strategies
Weakness Relies on yield = expected return Past may not predict future

6.2 When to Use Each Method

Use Method 1 When:

  • Portfolio is primarily fixed-income
  • You trust yield curve as forward indicator
  • R-squared is high (>50%) for most assets
  • Stable interest rate expectations
  • You want a market-anchored estimate

Use Method 2 When:

  • Portfolio includes trend-following assets
  • Historical returns show persistence
  • You want consistency with covariance
  • Momentum is economically important
  • Yield curve is inverted or unusual

6.3 Hybrid Approach

A natural extension is to blend the two methods based on R-squared:

Hybrid Formula
\[\mu_i^{hybrid} = R^2_i \cdot \mu_i^{M1} + (1 - R^2_i) \cdot \mu_i^{M2}\]

This automatically:

7. Complete Numerical Example

Learning Objectives

  • Work through a complete 2-asset example
  • Calculate expected returns using both methods
  • Apply the R-squared quality check

7.1 Setup

Given Data

ParameterBond (Euro Gov)Equity (MSCI EMU)
Volatility (\(\sigma\))4%16%
Beta on Factor 10.950.25

Market Rates:

  • 10Y German Bund yield: 2.8%
  • ESTR overnight rate: 2.4%

Historical Data:

  • Factor 1 time-weighted return: 3.5% (annualized)
  • Factor 1 volatility: 4%

7.2 Method 1 Calculation

Target Bond Return

\[r_{target} = \ln\left(\frac{1.028}{1.024}\right) = 0.0039 = 0.39\%\]

Calculate Lambda

\[\lambda = \frac{0.39\%}{0.95} = 0.41\%\]

Project to Assets

\[\mu_{bond} = 0.95 \times 0.41\% = +0.39\%\] \[\mu_{equity} = 0.25 \times 0.41\% = +0.10\%\]

7.3 Method 2 Calculation

Historical Factor Return

\[\hat{\mu}_{f_1} = 3.5\% \quad \text{(given)}\]

Project to Assets

\[\mu_{bond} = 0.95 \times 3.5\% = +3.33\%\] \[\mu_{equity} = 0.25 \times 3.5\% = +0.88\%\]

7.4 R-Squared Check

Calculate R-Squared

\[R^2_{bond} = \frac{0.95^2 \times 0.04^2}{0.04^2} = 0.90 \quad (90\%)\] \[R^2_{equity} = \frac{0.25^2 \times 0.04^2}{0.16^2} = 0.004 \quad (0.4\%)\]

7.5 Summary Table

Asset Method 1 Method 2 Difference R-squared Reliability
Bond +0.39% +3.33% 2.94% 90% High
Equity +0.10% +0.88% 0.78% 0.4% Unreliable

Key Takeaway

The methods give very different answers for bonds (3% difference!). Method 1 is forward-looking (current yield curve), Method 2 is backward-looking (historical momentum). Neither is "correct" - the choice depends on your investment philosophy.

For equities, both methods are unreliable because R-squared is only 0.4%. Consider using fundamental analysis or other approaches.

8. R Implementation Walkthrough

Learning Objectives

  • Understand the complete R code for both methods
  • Learn how to integrate with the BRISMA pipeline
  • Generate the market implied returns table

8.1 Prerequisites

Before running Julian's methods, you need outputs from the BRISMA factor model:

# Run the BRISMA pipeline first
source("R/examples/example1.R")

# You now have:
# - beta_id_id_comp.fit: Factor betas for each asset
# - ei_port: Eigenvalue decomposition
# - ret22_date_id_rm: Rolling returns of risk model assets
# - weight_time_garch: Time and GARCH weights

8.2 Method 1: Complete Implementation

# ===========================================================
# METHOD 1: 10Y Bond Calibration
# ===========================================================

# Market data (update these with current values)
yield_10y <- 0.028      # 10-year German Bund yield
estr_rate <- 0.024      # ESTR overnight rate

# Reference asset (10Y bond proxy)
asset_10year <- "RX_10Y_EUR"  # Or your bond index name
reference_id <- tbl_map_id_name %>%
  filter(name == asset_10year) %>%
  pull(id)

# Step 1: Calculate target excess return
return_asset_10year <- log((1 + yield_10y) / (1 + estr_rate))
cat("Target bond excess return:", round(return_asset_10year * 100, 2), "%\n")

# Step 2: Back out lambda
beta_ref <- beta_id_id_comp.fit["comp1", paste0(reference_id, ".fit")]
lambda_ <- return_asset_10year / beta_ref
cat("Factor premium (lambda):", round(lambda_ * 100, 2), "%\n")

# Step 3: Project to all assets
mu_method1 <- as.vector(t(beta_id_id_comp.fit["comp1", ]) * lambda_)
names(mu_method1) <- gsub("\\.fit$", "", colnames(beta_id_id_comp.fit))

# Step 4: Calculate R-squared
var_comp1 <- var(ret_roll_rm_comp[, 1])  # Factor 1 variance
var_assets <- diag(Q_port_emp)            # Asset variances
beta_vec <- as.vector(beta_id_id_comp.fit["comp1", ])

R_squared <- (beta_vec^2 * var_comp1) / var_assets[names(beta_vec)]

# Create results table
tbl_mir_method1 <- tibble(
  id = names(mu_method1),
  name = tbl_map_id_name$name[match(names(mu_method1), tbl_map_id_name$id)],
  mu_implied = mu_method1,
  R_squared = R_squared,
  reliable = R_squared > 0.50
)

print(tbl_mir_method1)

8.3 Method 2: Complete Implementation

# ===========================================================
# METHOD 2: Historical Performance
# ===========================================================

# Step 1: Get principal component returns
ret_roll_rm_comp <- ret22_date_id_rm %*% ei_port$vectors

# Step 2: Apply time and GARCH weights
# (These are already computed in the BRISMA pipeline)
weighted_returns <- weight_time_garch * ret_roll_rm_comp

# Step 3: Compute weighted average factor return
# Annualization factor
annualization <- (365.2425 / 7 * 5) / 22  # ~11.86 periods per year

comp1_return_weighted <- sum(weighted_returns[, 1]) * annualization
cat("Historical factor return:", round(comp1_return_weighted * 100, 2), "%\n")

# Step 4: Project to all assets
mu_method2 <- as.vector(t(beta_id_id_comp.fit["comp1", ]) * comp1_return_weighted)
names(mu_method2) <- gsub("\\.fit$", "", colnames(beta_id_id_comp.fit))

# Create results table
tbl_mir_method2 <- tibble(
  id = names(mu_method2),
  name = tbl_map_id_name$name[match(names(mu_method2), tbl_map_id_name$id)],
  mu_implied = mu_method2
)

print(tbl_mir_method2)

8.4 Combined Output

# ===========================================================
# COMBINED RESULTS TABLE
# ===========================================================

tbl_mir_combined <- tibble(
  id = names(mu_method1),
  name = tbl_map_id_name$name[match(names(mu_method1), tbl_map_id_name$id)],
  mu_method1 = mu_method1,
  mu_method2 = mu_method2,
  difference = abs(mu_method1 - mu_method2),
  R_squared = R_squared,
  reliable = R_squared > 0.50,
  recommended = ifelse(R_squared > 0.50, mu_method1, mu_method2)
) %>%
  arrange(desc(R_squared))

# Print nicely formatted
print(tbl_mir_combined, n = 20)

# Summary statistics
cat("\n=== Summary ===\n")
cat("Assets with reliable factor model (R² > 50%):", sum(tbl_mir_combined$reliable), "\n")
cat("Assets with unreliable factor model:", sum(!tbl_mir_combined$reliable), "\n")
cat("Average difference between methods:", round(mean(tbl_mir_combined$difference) * 100, 2), "%\n")

9. Practice Exercises

Learning Objectives

  • Apply the methods to new scenarios
  • Develop intuition for when methods diverge
  • Practice the R-squared calculation

Exercise 1: Inverted Yield Curve

Suppose the yield curve inverts: 10Y yield = 3.0%, overnight rate = 3.5%.

  1. Calculate the target bond excess return for Method 1
  2. What sign does \(\lambda\) have?
  3. What does this imply for equity expected returns?
Show Solution

1. Target return: \(\ln(1.030/1.035) = -0.48\%\)

2. Lambda is negative: \(\lambda = -0.48\%/0.95 = -0.51\%\)

3. All assets with positive beta have negative expected returns. This reflects the market's view that bonds will underperform cash.

Exercise 2: Low-Beta Asset

A CTA fund has \(\beta = 0.05\) on Factor 1 and volatility of 10%.

  1. Calculate the R-squared (assume factor volatility = 4%)
  2. Is the factor-based expected return reliable?
  3. What approach would you recommend?
Show Solution

1. R-squared: \(\frac{0.05^2 \times 0.04^2}{0.10^2} = \frac{0.000004}{0.01} = 0.0004 = 0.04\%\)

2. No - R-squared is essentially zero. Factor 1 explains almost none of the CTA's risk.

3. Use Method 2 (historical performance), fundamental analysis, or treat the CTA as a separate asset class with its own expected return estimate.

Exercise 3: Multi-Factor Extension

Suppose you have two factors with premiums \(\lambda_1 = 0.5\%\) and \(\lambda_2 = 2.0\%\).

An asset has betas: \(\beta_1 = 0.8\), \(\beta_2 = 0.3\).

  1. Calculate the expected return using both factors
  2. What is the contribution from each factor?
Show Solution

1. Expected return: \(\mu = 0.8 \times 0.5\% + 0.3 \times 2.0\% = 0.4\% + 0.6\% = 1.0\%\)

2. Factor 1 contributes 0.4%, Factor 2 contributes 0.6%. Factor 2 is more important despite lower beta because it has a higher premium.

Exercise 4: Hybrid Approach

Given:

  • Method 1 return: +1.0%
  • Method 2 return: +4.0%
  • R-squared: 60%

Calculate the hybrid expected return using the blending formula.

Show Solution

Hybrid formula: \(\mu^{hybrid} = R^2 \times \mu^{M1} + (1-R^2) \times \mu^{M2}\)

\(\mu^{hybrid} = 0.60 \times 1.0\% + 0.40 \times 4.0\% = 0.6\% + 1.6\% = 2.2\%\)

The hybrid gives 60% weight to Method 1 and 40% weight to Method 2.

10. References and Further Reading

10.1 Foundational Papers

Factor Pricing Theory:

Bond Yield and Expected Returns:

Momentum and Historical Returns:

10.2 Practitioner References

10.3 BRISMA Documentation

10.4 Academic Primer (Comprehensive Theory)

For a rigorous academic treatment of factor risk premia with real Fama-French data (T=726 months, 1963-2023), see:

Key topics covered in the academic primer: