SECTION 1: LEARNING OBJECTIVES

By the end of this lesson, you will be able to:

  • Define liquidity risk – funding liquidity risk and market liquidity risk.

  • Understand the key components – LCR, NSFR, and stress testing.

  • Apply liquidity risk measurement techniques.

  • Implement liquidity stress testing.

  • Measure liquidity risk using key metrics.

  • Understand the regulatory framework – Basel III, LCR, NSFR.

  • Develop a liquidity risk strategy for a digital bank.


SECTION 2: WHAT IS LIQUIDITY RISK?

2.1 Definition

Liquidity risk is the risk that a bank will not be able to meet its obligations as they fall due without incurring unacceptable losses. It has two components:

 
 
Component Description Example
Funding Liquidity Risk Inability to obtain sufficient funding. Deposit withdrawals, inability to roll over funding.
Market Liquidity Risk Inability to sell assets quickly without price concessions. Fire sale of assets during a crisis.
2.2 Liquidity Risk in Digital Banking
 
 
Aspect Digital Banking Exposure Mitigation
Deposit Volatility Digital deposits are more volatile. Diversified funding sources.
Real-Time Payments Faster outflows. Liquidity buffers.
Digital Channels Increased withdrawal speed. Stress testing.
Market Access Potential for rapid outflows. Contingency funding plan.

SECTION 3: LIQUIDITY RISK MEASUREMENT

3.1 Key Liquidity Ratios
 
 
Ratio Description Formula Target
Liquidity Coverage Ratio (LCR) Short-term liquidity (30 days). HQLA / Net Cash Outflows > 100%
Net Stable Funding Ratio (NSFR) Structural funding (1 year). ASF / RSF > 100%
Liquidity Gap Mismatch between assets and liabilities. Assets – Liabilities (by maturity) Positive.
Concentration Ratio Dependence on large depositors. Top 10 deposits / Total deposits < 20%
3.2 LCR Components
 
 
Component Description Examples
HQLA (High-Quality Liquid Assets) Assets that can be easily liquidated. Cash, government bonds.
Net Cash Outflows Outflows – Inflows (capped at 75% of outflows). Deposit withdrawals, funding maturities.
3.3 NSFR Components
 
 
Component Description Examples
ASF (Available Stable Funding) Stable funding sources. Equity, long-term debt, stable deposits.
RSF (Required Stable Funding) Funding required by assets. Loans, securities, illiquid assets.

SECTION 4: LIQUIDITY STRESS TESTING

4.1 Stress Testing Framework
text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    LIQUIDITY STRESS TESTING                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    SCENARIO DEFINITION                              │   │
│  │  (Idiosyncratic, market-wide, combined)                            │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│                                    v                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    CASH FLOW PROJECTION                             │   │
│  │  (Inflows and outflows under stress)                               │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│                                    v                                        │
│  └──────────────────────────────────────────────────────────────────────┘   │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    LIQUIDITY GAP ANALYSIS                           │   │
│  │  (Identify potential shortfalls)                                   │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│                                    v                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    CONTINGENCY PLANNING                             │   │
│  │  (Contingency funding plan, mitigants)                             │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
4.2 Stress Scenarios
 
 
Scenario Description Impact
Idiosyncratic Bank-specific stress. Loss of confidence, deposit withdrawals.
Market-Wide Systemic stress. Market disruption, asset price declines.
Combined Bank-specific + market-wide. Severe liquidity pressure.

SECTION 5: REGULATORY FRAMEWORK

5.1 Key Regulations
 
 
Regulation Focus Requirement
Basel III (LCR) Short-term liquidity. LCR > 100%.
Basel III (NSFR) Structural funding. NSFR > 100%.
EBA Guidelines Liquidity risk management. Stress testing, contingency plans.
PRA UK liquidity requirements. LCR, NSFR, stress testing.
5.2 Regulatory Expectations
 
 
Expectation Description Implementation
LCR Compliance Maintain LCR > 100%. HQLA buffer, monitoring.
NSFR Compliance Maintain NSFR > 100%. Stable funding.
Stress Testing Regular liquidity stress testing. Internal stress tests.
Contingency Funding Plan Plan for liquidity crises. CFP, action triggers.

SECTION 6: IMPLEMENTATION IN PYTHON – LIQUIDITY RISK

python
# ===================================================================
# MODULE 8, LESSON 5: LIQUIDITY RISK MANAGEMENT
# ===================================================================

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

print("="*70)
print("LIQUIDITY RISK MANAGEMENT IN DIGITAL BANKING")
print("="*70)

# ----------------------------------------------------------------
# PART A: BALANCE SHEET SIMULATION
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART A: Balance Sheet Simulation")
print("-"*60)

# Simulate bank balance sheet
assets = {
    'Cash': 200,
    'Government Bonds': 300,
    'Corporate Bonds': 200,
    'Loans': 800,
    'Other Assets': 100
}
total_assets = sum(assets.values())

liabilities = {
    'Retail Deposits': 500,
    'Wholesale Deposits': 300,
    'Short-term Borrowings': 200,
    'Long-term Debt': 300,
    'Other Liabilities': 100
}
total_liabilities = sum(liabilities.values())

equity = total_assets - total_liabilities

balance_sheet = pd.DataFrame({
    'Item': list(assets.keys()) + list(liabilities.keys()) + ['Equity'],
    'Category': ['Asset']*len(assets) + ['Liability']*len(liabilities) + ['Equity'],
    'Amount': list(assets.values()) + list(liabilities.values()) + [equity]
})

print("Balance Sheet Summary:")
print(f"Total Assets: ${total_assets:,.0f}M")
print(f"Total Liabilities: ${total_liabilities:,.0f}M")
print(f"Equity: ${equity:,.0f}M")
print(f"Equity Ratio: {equity/total_assets:.2%}")

# ----------------------------------------------------------------
# PART B: LCR CALCULATION
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART B: Liquidity Coverage Ratio (LCR)")
print("-"*60)

# HQLA calculation
hqla_level1 = assets['Cash'] + assets['Government Bonds']  # Level 1 (0% haircut)
hqla_level2a = assets['Corporate Bonds'] * 0.5  # Level 2A (20% haircut)

# Cap Level 2 at 40% of total HQLA
hqla_level2 = hqla_level2a
hqla_cap = 0.4 * (hqla_level1 + hqla_level2)
if hqla_level2 > hqla_cap:
    hqla_level2_adj = hqla_cap
else:
    hqla_level2_adj = hqla_level2

hqla_total = hqla_level1 + hqla_level2_adj

print("HQLA Components:")
print(f"  Level 1: ${hqla_level1:,.0f}M")
print(f"  Level 2 (capped): ${hqla_level2_adj:,.0f}M")
print(f"  Total HQLA: ${hqla_total:,.0f}M")

# Cash outflows (30-day stress scenario)
outflows = {
    'Retail Deposits (stable)': liabilities['Retail Deposits'] * 0.05,
    'Retail Deposits (unstable)': liabilities['Retail Deposits'] * 0.10 * 0.5,
    'Wholesale Deposits': liabilities['Wholesale Deposits'] * 0.40,
    'Short-term Borrowings': liabilities['Short-term Borrowings'] * 1.0,
    'Undrawn Commitments': 20
}
total_outflows = sum(outflows.values())

# Cash inflows
inflows = {
    'Loan Repayments': 30,
    'Securities Maturities': 20,
    'Other Inflows': 10
}
total_inflows = sum(inflows.values())

# Net cash outflows (inflows capped at 75% of outflows)
inflow_cap = 0.75 * total_outflows
net_outflows = total_outflows - min(total_inflows, inflow_cap)

lcr = hqla_total / net_outflows

print("\n30-Day Net Cash Outflows:")
print(f"  Total Outflows: ${total_outflows:,.0f}M")
print(f"  Total Inflows: ${total_inflows:,.0f}M")
print(f"  Net Outflows (capped): ${net_outflows:,.0f}M")
print(f"\nLiquidity Coverage Ratio (LCR): {lcr:.2f} ({lcr*100:.0f}%)")
if lcr >= 1.0:
    print("  ✓ LCR meets regulatory requirement (≥ 100%)")
else:
    print("  ⚠ LCR is below 100% – action required")

# ----------------------------------------------------------------
# PART C: NSFR CALCULATION
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART C: Net Stable Funding Ratio (NSFR)")
print("-"*60)

# Available Stable Funding (ASF)
asf_factors = {
    'Equity': 1.0,
    'Long-term Debt': 1.0,
    'Retail Deposits (stable)': 0.95,
    'Retail Deposits (unstable)': 0.90,
    'Wholesale Deposits': 0.50,
    'Short-term Borrowings': 0.0,
    'Other Liabilities': 0.0
}

asf_amount = (
    equity * asf_factors['Equity'] +
    liabilities['Long-term Debt'] * asf_factors['Long-term Debt'] +
    liabilities['Retail Deposits'] * 0.5 * asf_factors['Retail Deposits (stable)'] +
    liabilities['Retail Deposits'] * 0.5 * asf_factors['Retail Deposits (unstable)'] +
    liabilities['Wholesale Deposits'] * asf_factors['Wholesale Deposits']
)

print(f"Available Stable Funding (ASF): ${asf_amount:,.0f}M")

# Required Stable Funding (RSF)
rsf_factors = {
    'Cash': 0.0,
    'Government Bonds': 0.05,
    'Corporate Bonds': 0.50,
    'Loans': 0.65,
    'Other Assets': 0.50
}

rsf_amount = (
    assets['Cash'] * rsf_factors['Cash'] +
    assets['Government Bonds'] * rsf_factors['Government Bonds'] +
    assets['Corporate Bonds'] * rsf_factors['Corporate Bonds'] +
    assets['Loans'] * rsf_factors['Loans'] +
    assets['Other Assets'] * rsf_factors['Other Assets']
)

print(f"Required Stable Funding (RSF): ${rsf_amount:,.0f}M")

nsfr = asf_amount / rsf_amount
print(f"\nNet Stable Funding Ratio (NSFR): {nsfr:.2f} ({nsfr*100:.0f}%)")
if nsfr >= 1.0:
    print("  ✓ NSFR meets regulatory requirement (≥ 100%)")
else:
    print("  ⚠ NSFR is below 100% – action required")

# ----------------------------------------------------------------
# PART D: LIQUIDITY GAP ANALYSIS
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART D: Liquidity Gap Analysis")
print("-"*60)

# Define maturity buckets
maturity_buckets = ['< 1 month', '1-3 months', '3-6 months', '6-12 months', '> 1 year']

# Asset distribution by maturity
asset_maturity = {
    'Cash': [100, 0, 0, 0, 0],
    'Government Bonds': [20, 30, 50, 100, 100],
    'Corporate Bonds': [10, 20, 30, 40, 100],
    'Loans': [20, 40, 80, 160, 500],
    'Other Assets': [10, 10, 20, 20, 40]
}

# Liability distribution by maturity
liability_maturity = {
    'Retail Deposits': [100, 100, 100, 100, 100],
    'Wholesale Deposits': [150, 100, 50, 0, 0],
    'Short-term Borrowings': [200, 0, 0, 0, 0],
    'Long-term Debt': [0, 0, 0, 50, 250],
    'Other Liabilities': [20, 20, 20, 20, 20]
}

# Calculate liquidity gap
asset_gap = pd.DataFrame(asset_maturity, index=maturity_buckets)
liability_gap = pd.DataFrame(liability_maturity, index=maturity_buckets)
liquidity_gap = asset_gap.sum(axis=1) - liability_gap.sum(axis=1)

print("Liquidity Gap by Maturity Bucket ($M):")
gap_df = pd.DataFrame({
    'Bucket': maturity_buckets,
    'Assets': asset_gap.sum(axis=1).values,
    'Liabilities': liability_gap.sum(axis=1).values,
    'Gap': liquidity_gap.values
})
print(gap_df.to_string(index=False))

# Visualise
fig, ax = plt.subplots(figsize=(12, 6))
x = np.arange(len(maturity_buckets))
width = 0.35

ax.bar(x - width/2, asset_gap.sum(axis=1), width, label='Assets', color='green', alpha=0.7)
ax.bar(x + width/2, liability_gap.sum(axis=1), width, label='Liabilities', color='red', alpha=0.7)

ax.set_xlabel('Maturity Bucket')
ax.set_ylabel('Amount ($M)')
ax.set_title('Liquidity Gap: Assets vs Liabilities by Maturity')
ax.set_xticks(x)
ax.set_xticklabels(maturity_buckets)
ax.legend()
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('liquidity_gap.png', dpi=300, bbox_inches='tight')
plt.show()
print("Liquidity gap visualisation saved as 'liquidity_gap.png'")

# ----------------------------------------------------------------
# PART E: LIQUIDITY STRESS TESTING
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART E: Liquidity Stress Testing")
print("-"*60)

# Define stress scenarios
stress_scenarios = {
    'Baseline': {'deposit_runoff': 0.05, 'funding_rollover': 0.1, 'asset_sale': 0.0},
    'Moderate Stress': {'deposit_runoff': 0.15, 'funding_rollover': 0.3, 'asset_sale': 0.05},
    'Severe Stress': {'deposit_runoff': 0.30, 'funding_rollover': 0.6, 'asset_sale': 0.10},
    'Extreme Stress': {'deposit_runoff': 0.50, 'funding_rollover': 0.9, 'asset_sale': 0.20}
}

def liquidity_gap_stress(scenario, assets, liabilities, hqla):
    """Calculate liquidity gap under stress."""
    runoff = scenario['deposit_runoff'] * liabilities['Retail Deposits']
    wholesale_runoff = scenario['funding_rollover'] * liabilities['Wholesale Deposits']
    short_term_runoff = scenario['funding_rollover'] * liabilities['Short-term Borrowings']
    
    total_outflows = runoff + wholesale_runoff + short_term_runoff
    
    # Asset sales at discount
    asset_sale_need = max(0, total_outflows - hqla)
    if asset_sale_need > 0:
        sale_proceeds = asset_sale_need * (1 - scenario['asset_sale'])
        liquidity_gap = total_outflows - hqla - sale_proceeds
    else:
        liquidity_gap = total_outflows - hqla
    
    return liquidity_gap

stress_results = []
for name, scenario in stress_scenarios.items():
    gap = liquidity_gap_stress(scenario, assets, liabilities, hqla_total)
    stress_results.append({
        'Scenario': name,
        'Liquidity Gap': gap,
        'LCR': hqla_total / max(0.1, (gap + hqla_total))
    })

stress_df = pd.DataFrame(stress_results)
print("Liquidity Stress Test Results:")
print(stress_df.to_string(index=False))

# Visualise
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(len(stress_df))
bars = ax.bar(x, stress_df['Liquidity Gap'], 
              color=['green', 'yellow', 'orange', 'red'], alpha=0.7)
ax.axhline(y=0, color='black', linestyle='-', alpha=0.5)
ax.set_xticks(x)
ax.set_xticklabels(stress_df['Scenario'])
ax.set_ylabel('Liquidity Gap ($M)')
ax.set_title('Liquidity Stress Testing – Gap under Scenarios')
for bar, val in zip(bars, stress_df['Liquidity Gap']):
    ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5, 
            f'${val:.0f}M', ha='center', va='bottom')
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('liquidity_stress.png', dpi=300, bbox_inches='tight')
plt.show()
print("Liquidity stress visualisation saved as 'liquidity_stress.png'")

# ----------------------------------------------------------------
# PART F: LIQUIDITY METRICS DASHBOARD
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART F: Liquidity Metrics Dashboard")
print("-"*60)

liquidity_metrics = pd.DataFrame({
    'Metric': [
        'Liquidity Coverage Ratio (LCR)',
        'Net Stable Funding Ratio (NSFR)',
        'Liquidity Gap (1-month)',
        'Concentration Ratio',
        'HQLA Buffer',
        'Deposit Volatility',
        'Funding Diversification',
        'Stress Test Pass Rate'
    ],
    'Current Value': [
        f'{lcr*100:.0f}%',
        f'{nsfr*100:.0f}%',
        f'${liquidity_gap[0]:.0f}M',
        '18%',
        f'${hqla_total:.0f}M',
        '12%',
        '72%',
        '75%'
    ],
    'Target Value': [
        '> 100%',
        '> 100%',
        '> $0M',
        '< 20%',
        '> $500M',
        '< 10%',
        '> 80%',
        '> 90%'
    ],
    'Status': ['🟢', '🟢', '🟢', '🟢', '🟢', '🟡', '🟡', '🟡']
})

print("Liquidity Metrics Dashboard:")
print(liquidity_metrics.to_string(index=False))

# ----------------------------------------------------------------
# PART G: SUMMARY AND RECOMMENDATIONS
# ----------------------------------------------------------------

print("\n" + "="*70)
print("PART G: Summary and Recommendations")
print("="*70)

print("""
Liquidity Risk Management – Key Takeaways:

1. Liquidity risk includes funding and market liquidity risk.
2. LCR measures 30-day liquidity (HQLA / Net Cash Outflows).
3. NSFR measures 1-year structural funding (ASF / RSF).
4. Liquidity gap analysis identifies maturity mismatches.
5. Stress testing evaluates resilience under adverse scenarios.
6. Regulatory framework: Basel III (LCR, NSFR).
7. Key metrics: LCR, NSFR, liquidity gap, concentration ratio.

Recommendations:
  - Maintain LCR > 100% and NSFR > 100%.
  - Conduct regular liquidity stress testing.
  - Diversify funding sources.
  - Maintain HQLA buffer.
  - Develop contingency funding plan.
  - Monitor liquidity metrics continuously.
""")

print("="*70)
print("END OF LESSON 5 – MODULE 8")
print("="*70)

SECTION 7: SUMMARY FOR THE DATA PRACTITIONER

  • Liquidity risk includes funding liquidity risk and market liquidity risk.

  • LCR measures short-term liquidity (30-day horizon) with HQLA / Net Cash Outflows > 100%.

  • NSFR measures structural funding (1-year horizon) with ASF / RSF > 100%.

  • Liquidity gap analysis identifies maturity mismatches between assets and liabilities.

  • Stress testing evaluates liquidity resilience under adverse scenarios (idiosyncratic, market-wide, combined).

  • Regulatory framework includes Basel III (LCR, NSFR) and EBA guidelines.

  • Key metrics include LCR, NSFR, liquidity gap, concentration ratio, HQLA buffer, and deposit volatility.


SECTION 8: RECOMMENDED NEXT STEPS

  1. Maintain LCR > 100% and NSFR > 100%.

  2. Conduct regular liquidity stress testing.

  3. Diversify funding sources.

  4. Maintain HQLA buffer.

  5. Develop contingency funding plan.

  6. Monitor liquidity metrics continuously.

  7. Prepare for Lesson 6: Model Risk and AI Risk Management.


[END OF LESSON 5 – MODULE 8]