Recommended resources
The freely available resources this lesson will direct you to.
Hello! Welcome back to our journey into real estate investment analysis.
In our last lesson, we built tornado diagrams to pinpoint which individual assumptions, like exit cap rate or rental income, have the biggest impact on our investment returns. This is powerful, but it has a limitation: it analyzes variables in isolation. In the real world, factors often move in tandem. A strong economy might boost rents and compress cap rates simultaneously. A recession might do the opposite.
This brings us to today's topic. Our goal is to create scenario models (best case, base case, worst case) for investment outcomes. Instead of tweaking one variable at a time, we will build a few distinct, plausible "stories" about the future. This will give us a more realistic understanding of the potential range of returns by modeling how multiple key drivers might interact.
1. From Sensitivity to Scenarios
While sensitivity analysis helps us understand the impact of individual variables, scenario analysis evaluates the effect of a particular combination of events.
To start, let's get a formal definition and understand the three classic scenarios you'll build for almost any investment analysis.
This article from the Corporate Finance Institute (CFI) provides a concise definition of scenario analysis and lays out the 'Base', 'Worst', and 'Best' cases. It's a foundational concept in all financial modeling.
Please read the sections 'What is Scenario Analysis?', 'Generating Cases to be Used in Scenario Analysis?', and 'What are the Benefits of Performing Scenario Analysis?'. Focus on the descriptions of the Base, Worst, and Best case scenarios.
As the article highlights, the three core scenarios are:
- Base Case: This is your most probable story, built using your primary, most-researched assumptions. All the models we've built so far have essentially been base-case models.
- Worst Case (Downside/Pessimistic): This story models an unfavorable economic environment. For a real estate investment, this could mean lower rent growth, higher vacancy rates, increased operating expenses, and a higher exit cap rate (leading to a lower sale price).
- Best Case (Upside/Optimistic): This story models a boom. Here, you'd assume higher rent growth, lower vacancy, and a lower exit cap rate (leading to a higher sale price).
The key is that the assumptions within each scenario must be internally consistent. It would be illogical to model a "worst case" with booming rental growth. By grouping these related changes, you create a much more insightful picture than a simple one-variable sensitivity table can provide. This is a standard step in any professional financial analysis, as reinforced in broader guides on financial modeling like the one from Growth Equity Interview Guide.
2. Structuring a Model for Scenarios
To analyze different scenarios without rebuilding your model each time, you need to structure it dynamically. The industry-standard approach, whether in Excel or code, is to separate your assumptions from your calculations.
The core idea is:
- Define a complete set of assumptions for each scenario (Best, Base, Worst).
- Create a single "Live" or "Active" set of assumptions that the main financial model will use.
- Implement a switch that allows you to instantly change which scenario's assumptions are fed into the "Live" set.
This makes your model clean, powerful, and easy to audit. Let's see how this is done in practice. The following video demonstrates this structure perfectly in Excel, which is a great way to visualize the concept before we translate it to Python.
Scenario Analysis in Excel: Financial Modeling
This video from the Corporate Finance Institute demonstrates how to set up an Excel model to handle multiple scenarios using a dynamic switch. The logic is directly transferable to how we'll structure our Python code.
Watch from the beginning to 06:29. Pay close attention to: How the assumption sets are laid out for an 'upside' and 'downside' case (00:00-03:30). The creation of a 'live case' section and a 'switch' (a single cell to control the model). The use of the CHOOSE function to dynamically pull the correct assumptions into the live model (03:30-06:29).
The CHOOSE function in Excel is the engine here. It selects a value from a list based on an index number. By linking the rest of your model to the output of CHOOSE, you can flip between entire economic realities with the change of a single number.
3. Implementing Scenario Analysis in Python
Given your background, you can immediately see how this modular structure translates beautifully to code. Instead of spreadsheet sections and CHOOSE functions, we can use dictionaries or objects to hold our assumption sets and simply pass the desired set into our calculation engine.
Let's adapt the Python code from our previous lesson. We will define three dictionaries, one for each scenario, and then run our calculate_npv function for each to see the range of outcomes.
import numpy as np
# --- 1. Simplified Financial Model (from previous lesson) ---
def calculate_npv(params, purchase_price=1_000_000, discount_rate=0.08):
"""
Calculates NPV for a 5-year holding period based on a set of parameters.
"""
annual_rent = params['monthly_rent'] * 12
op_ex = params['opex_ratio'] * annual_rent
# Calculate NOI for 5 years. Assuming constant NOI for simplicity.
noi_y1 = annual_rent * (1 - params['vacancy_rate']) - op_ex
# Calculate cash flows
cash_flows = [noi_y1] * 5
# Calculate reversion value (sale price)
sale_price = noi_y1 / params['exit_cap_rate']
cash_flows[-1] += sale_price
# Initial investment
initial_investment = -purchase_price
# Combine all cash flows
all_cash_flows = [initial_investment] + cash_flows
# Calculate NPV
npv = np.npv(discount_rate, all_cash_flows)
return npv
# --- 2. Define Assumption Sets for Each Scenario ---
# Base Case: Our most likely set of assumptions
base_case = {
'name': 'Base Case',
'monthly_rent': 5000,
'vacancy_rate': 0.05,
'opex_ratio': 0.35,
'exit_cap_rate': 0.06
}
# Worst Case: A pessimistic, but plausible, economic downturn
worst_case = {
'name': 'Worst Case',
'monthly_rent': 4600, # Rents fall by 8%
'vacancy_rate': 0.10, # Vacancy doubles
'opex_ratio': 0.38, # Expenses are harder to control
'exit_cap_rate': 0.075 # Market is riskier, buyers demand higher returns
}
# Best Case: An optimistic, but plausible, economic boom
best_case = {
'name': 'Best Case',
'monthly_rent': 5400, # Rents rise by 8%
'vacancy_rate': 0.03, # High demand, low vacancy
'opex_ratio': 0.34, # Expenses are well-managed
'exit_cap_rate': 0.05 # Market is hot, buyers accept lower initial returns
}
# --- 3. Run the Analysis for Each Scenario ---
scenarios = [worst_case, base_case, best_case]
results = []
print("--- Scenario Analysis Results ---")
for scenario in scenarios:
npv = calculate_npv(scenario)
results.append({'scenario': scenario['name'], 'npv': npv})
print(f"Scenario: {scenario['name']:<12} | NPV: {npv:,.0f}€")
# You could also visualize this with a simple bar chart
import matplotlib.pyplot as plt
names = [r['scenario'] for r in results]
npvs = [r['npv'] for r in results]
plt.figure(figsize=(8, 5))
bars = plt.bar(names, npvs, color=['salmon', 'cornflowerblue', 'lightgreen'])
plt.ylabel('Net Present Value (NPV) in €')
plt.title('NPV Outcomes by Scenario')
# Add values on top of bars
for bar in bars:
yval = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2.0, yval, f'{yval:,.0f}€', va='bottom', ha='center')
plt.show()
This Python script cleanly separates the "what if" (the scenario dictionaries) from the "how" (the calculate_npv function). This is a robust and scalable pattern. You could easily expand this by adding more variables to each scenario dictionary (e.g., rent growth rate, inflation) without changing the core logic.
Test your understanding!
Looking at the Python code, the worst_case dictionary models a downturn by adjusting four key variables.
Imagine a truly severe crisis where, in addition to the existing pessimistic assumptions, lenders dramatically tighten their standards, making it much harder for you to secure financing for the initial purchase.
Which parameter in the calculate_npv function's signature would you need to adjust to model this? Would you need to add a new key to the scenario dictionaries? Explain your reasoning.
Show answer
You would need to adjust the purchase_price. In this crisis, tighter lending might mean you need to contribute a larger down payment, effectively increasing your initial cash outlay, or that you can only afford a lower purchase price overall.
You would not necessarily need to add a new key to the scenario dictionaries. Since purchase_price is a direct argument to the calculate_npv function, you could model this by calling the function with a different value for that specific scenario. For example: calculate_npv(worst_case, purchase_price=1_100_000) if your initial cash investment increased.
However, for better organization and to keep all assumptions together, a better practice would be to add a 'purchase_price': 1100000 key-value pair to the worst_case dictionary and modify the main loop to pass this value to the function.
Conclusion
Today, we've moved beyond single-variable sensitivity to build a more holistic view of investment risk. By creating coherent best-case, base-case, and worst-case scenarios, you can tell a compelling story about the potential future of your investment and establish a plausible range for its financial outcomes.
Key Takeaways:
- Scenario Analysis involves changing multiple, related variables at once to model distinct future "stories" (e.g., a recession, a boom).
- It complements Sensitivity Analysis by providing a more realistic range of outcomes, as variables rarely move in isolation.
- The three fundamental scenarios are Best Case, Base Case, and Worst Case.
- A robust model is structured to separate assumption sets from the calculation engine, using a dynamic switch (like Excel's
CHOOSEor function arguments in Python) to toggle between scenarios.
Preview of the Next Lesson:
Scenario analysis is powerful, but it only gives us a few discrete data points (Best, Base, Worst). What if we want to understand the probability of achieving a certain return? What are the odds that the NPV will be positive? To answer that, we need to analyze thousands, or even millions, of potential scenarios.
In our next lesson, we will do exactly that by learning how to perform a Monte Carlo simulation. This technique will allow us to generate a full probability distribution of investment returns, giving you the most comprehensive view of risk and reward yet.