SECTION 1: LEARNING OBJECTIVES

This final lesson consolidates everything you have learned across the diploma into a comprehensive capstone project. By the end of this lesson, you will be able to:

  • Design and implement an end-to-end financial data analytics solution covering data ingestion, cleaning, analysis, modelling, and deployment.

  • Apply the skills from all previous modules: data warehousing (Module 1), EDA (Module 2), statistics (Module 3), machine learning (Module 4), risk analytics (Module 5), and advanced topics (Module 6).

  • Build a credit risk assessment dashboard for a bank – from raw data to interactive visualisation.

  • Integrate multiple data sources – structured customer data, transactional data, and external economic indicators.

  • Develop and validate a predictive model (logistic regression / XGBoost) for loan default prediction.

  • Calculate expected loss and stress test the portfolio under macroeconomic scenarios.

  • Deploy a simple interactive dashboard using Streamlit or a similar tool.

  • Document the project as a portfolio piece to demonstrate your skills.


SECTION 2: PROJECT OVERVIEW – CREDIT RISK ASSESSMENT DASHBOARD

Scenario: You are a data analyst at a mid-sized bank. The Credit Risk team wants a dashboard that:

  • Aggregates customer and loan data.

  • Predicts the probability of default (PD) for each loan.

  • Calculates Expected Loss (EL) at the portfolio level.

  • Performs scenario analysis (stress testing) for different economic conditions.

  • Allows credit officers to drill down into individual loan details.

Deliverables:

  1. A Python script that processes data, builds the model, and generates a report.

  2. An interactive dashboard (Streamlit/Plotly Dash) with:

    • Portfolio overview (total exposure, EL, PD distribution).

    • Individual loan-level predictions and explanations (SHAP).

    • Scenario analysis sliders (GDP growth, unemployment).

Data Sources:

  • Internal loan data (simulated): customer demographics, financial ratios, loan terms.

  • External economic indicators (simulated): GDP growth, unemployment rate, inflation.


SECTION 3: PROJECT STEPS

 
 
Step Description Relevant Module
1. Data Ingestion Load data from multiple sources (CSV, API, database). Module 1
2. Data Cleaning Handle missing values, outliers, and inconsistencies. Module 2
3. Feature Engineering Create new features (e.g., debt-to-income ratio, credit utilisation). Module 2
4. Exploratory Analysis Understand distributions, correlations, and relationships. Module 2
5. Model Building Train a logistic regression / XGBoost model. Module 4
6. Model Evaluation Validate model (AUC, KS, calibration, fairness). Modules 4, 5, 6
7. Risk Calculation Compute PD, LGD, EAD, EL, and economic capital. Module 5
8. Stress Testing Apply macroeconomic shocks to portfolio. Module 5
9. Dashboard Visualise results with interactive dashboard. All modules
10. Documentation Write a comprehensive report. All modules

SECTION 4: IMPLEMENTATION IN PYTHON – CAPSTONE PROJECT

Given the length constraints, we provide the core implementation framework. The full code is available in the course repository.

python
# ===================================================================
# MODULE 6, LESSON 8: CAPSTONE PROJECT – CREDIT RISK DASHBOARD
# ===================================================================

"""
Project Structure:
├── data/
│   ├── loan_data.csv
│   ├── macro_data.csv
├── src/
│   ├── data_prep.py
│   ├── model.py
│   ├── risk.py
│   ├── dashboard.py
├── notebooks/
│   ├── eda.ipynb
│   ├── modeling.ipynb
├── requirements.txt
├── README.md
└── run.py
"""

# We'll provide the main components as code cells.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb
from sklearn.metrics import roc_auc_score, classification_report
import shap
import streamlit as st
from io import StringIO
import warnings
warnings.filterwarnings('ignore')

print("="*70)
print("CAPSTONE PROJECT – CREDIT RISK DASHBOARD")
print("="*70)

# ----------------------------------------------------------------
# PART A: DATA GENERATION (simulate internal and external data)
# ----------------------------------------------------------------

def generate_data(n=10000):
    """Generate synthetic loan and macro data."""
    # Internal loan data
    np.random.seed(42)
    df = pd.DataFrame({
        'loan_id': range(1, n+1),
        'age': np.random.normal(45, 12, n).clip(22, 75).astype(int),
        'income': np.random.gamma(5, 15, n) + 20,
        'dti': np.random.beta(2, 5, n) * 60,
        'credit_score': np.random.normal(700, 50, n).clip(550, 850).astype(int),
        'loan_amount': np.random.gamma(4, 50, n) + 30,
        'loan_term': np.random.choice([12, 24, 36, 48, 60, 72], n),
        'employment_years': np.random.gamma(3, 5, n).clip(0, 30).astype(int),
        'home_owner': np.random.binomial(1, 0.65, n),
        'marital_status': np.random.choice([0, 1, 2], n, p=[0.4, 0.4, 0.2]),  # 0: single, 1: married, 2: other
        'education': np.random.choice([0, 1, 2, 3], n, p=[0.2, 0.3, 0.3, 0.2])  # 0: high school, 1: some college, 2: bachelor, 3: post-grad
    })
    # Economic indicators (add as columns)
    # Simulate time-varying macro data (quarterly)
    quarters = np.repeat(np.arange(1, 21), n/20)  # 20 quarters
    quarters = quarters[:n]
    # GDP growth, unemployment, inflation
    gdp = np.random.normal(0.025, 0.01, 20)[quarters.astype(int)-1]
    unemp = np.random.normal(0.05, 0.005, 20)[quarters.astype(int)-1]
    inf = np.random.normal(0.02, 0.005, 20)[quarters.astype(int)-1]
    df['gdp'] = gdp
    df['unemployment'] = unemp
    df['inflation'] = inf
    # Generate default based on features (logistic)
    log_odds = (-4.5 + 0.04*df['dti'] - 0.005*df['credit_score'] + 0.01*(df['loan_amount']/1000)
                + 0.02*df['employment_years'] - 0.01*df['age'] + 0.3*df['home_owner']
                - 0.5*df['marital_status'] - 0.3*df['education'] - 1.5*df['gdp'] + 3*df['unemployment'])
    prob = 1/(1+np.exp(-log_odds))
    df['default'] = np.random.binomial(1, prob)
    # LGD (loss given default)
    df['lgd'] = np.where(df['home_owner'] == 1, 
                         np.random.normal(0.35, 0.10, n).clip(0.05, 0.80),
                         np.random.normal(0.65, 0.10, n).clip(0.05, 0.95))
    # EAD = loan amount (for term loans)
    df['ead'] = df['loan_amount']
    return df

# Generate data
df_loan = generate_data(10000)

# Save to CSV for dashboard
df_loan.to_csv('loan_data.csv', index=False)

print("Data generated and saved.")
print(f"Shape: {df_loan.shape}")
print(f"Default rate: {df_loan['default'].mean():.4f}")

# ----------------------------------------------------------------
# PART B: DATA PREPARATION AND MODEL BUILDING
# ----------------------------------------------------------------

def build_model(df):
    """Train a default prediction model."""
    features = ['age', 'income', 'dti', 'credit_score', 'loan_amount', 'loan_term',
                'employment_years', 'home_owner', 'marital_status', 'education',
                'gdp', 'unemployment', 'inflation']
    X = df[features]
    y = df['default']
    
    # Train-test split
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
    
    # Scale
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    # Model (XGBoost)
    model = xgb.XGBClassifier(n_estimators=100, max_depth=5, learning_rate=0.1,
                              random_state=42, use_label_encoder=False, eval_metric='logloss')
    model.fit(X_train_scaled, y_train)
    
    # Predictions
    y_pred_proba = model.predict_proba(X_test_scaled)[:, 1]
    auc = roc_auc_score(y_test, y_pred_proba)
    print(f"Model AUC: {auc:.4f}")
    
    # Save model and scaler
    import joblib
    joblib.dump(model, 'model.pkl')
    joblib.dump(scaler, 'scaler.pkl')
    joblib.dump(features, 'features.pkl')
    
    return model, scaler, features, X_test, y_test, y_pred_proba

# Build the model
model, scaler, features, X_test, y_test, y_pred_proba = build_model(df_loan)

# ----------------------------------------------------------------
# PART C: RISK CALCULATION
# ----------------------------------------------------------------

def calculate_risk(df, model, scaler, features):
    """Compute PD, EL, and economic capital."""
    X = df[features]
    X_scaled = scaler.transform(X)
    pd_pred = model.predict_proba(X_scaled)[:, 1]
    df['pd'] = pd_pred
    df['el'] = df['pd'] * df['lgd'] * df['ead']
    # Economic capital (Vasicek)
    from scipy.stats import norm
    rho = 0.12
    z = norm.ppf(0.999)
    pd_adj = norm.cdf((norm.ppf(df['pd']) + np.sqrt(rho) * z) / np.sqrt(1 - rho))
    df['ul'] = df['lgd'] * (pd_adj - df['pd']) * df['ead']
    df['ul'] = np.maximum(df['ul'], 0)
    return df

df_risk = calculate_risk(df_loan, model, scaler, features)

print(f"Total EL: ${df_risk['el'].sum():,.2f}")
print(f"Total UL (99.9%): ${df_risk['ul'].sum():,.2f}")
print(f"EL as % of portfolio: {df_risk['el'].sum() / df_risk['ead'].sum() * 100:.2f}%")

# ----------------------------------------------------------------
# PART D: STRESS TESTING
# ----------------------------------------------------------------

def stress_test(df, model, scaler, features, gdp_shock, unemp_shock):
    """Apply macroeconomic shocks and recalc EL."""
    df_stressed = df.copy()
    # Apply shocks: GDP shock shifts the gdp feature, unemployment shock shifts unemployment
    df_stressed['gdp'] = df_stressed['gdp'] + gdp_shock
    df_stressed['unemployment'] = df_stressed['unemployment'] + unemp_shock
    # Recalculate PD
    X_stressed = df_stressed[features]
    X_scaled_stressed = scaler.transform(X_stressed)
    pd_stressed = model.predict_proba(X_scaled_stressed)[:, 1]
    df_stressed['pd_stressed'] = pd_stressed
    df_stressed['el_stressed'] = pd_stressed * df_stressed['lgd'] * df_stressed['ead']
    return df_stressed

# Define scenarios
scenarios = {
    'Baseline': (0.0, 0.0),
    'Adverse': (-0.02, 0.03),
    'Severely Adverse': (-0.05, 0.06)
}

stress_results = []
for name, (gdp_shock, unemp_shock) in scenarios.items():
    df_scenario = stress_test(df_risk, model, scaler, features, gdp_shock, unemp_shock)
    el_total = df_scenario['el_stressed'].sum()
    stress_results.append({'Scenario': name, 'EL': el_total, 'Increase %': (el_total/df_risk['el'].sum() - 1)*100})

print("\nStress Test Results:")
for res in stress_results:
    print(f"{res['Scenario']}: EL = ${res['EL']:,.2f} (increase {res['Increase %']:.1f}%)")

# ----------------------------------------------------------------
# PART E: DASHBOARD (Streamlit) – Code Snippet
# ----------------------------------------------------------------

st.markdown("""
# Credit Risk Dashboard

## Portfolio Overview
""")

# Load data (in real dashboard, use st.cache)
df = pd.read_csv('loan_data.csv')
model = joblib.load('model.pkl')
scaler = joblib.load('scaler.pkl')
features = joblib.load('features.pkl')

# Compute metrics
total_exposure = df['ead'].sum()
avg_pd = df['pd'].mean()
total_el = df['el'].sum()
ul_99 = df['ul'].sum()

col1, col2, col3, col4 = st.columns(4)
col1.metric("Total Exposure", f"${total_exposure:,.0f}")
col2.metric("Average PD", f"{avg_pd:.2%}")
col3.metric("Expected Loss", f"${total_el:,.0f}")
col4.metric("Economic Capital (99.9%)", f"${ul_99:,.0f}")

# PD Distribution
st.subheader("PD Distribution")
fig, ax = plt.subplots()
ax.hist(df['pd'], bins=50, edgecolor='black', alpha=0.7)
st.pyplot(fig)

# Scenario Analysis
st.subheader("Scenario Analysis")
gdp_slider = st.slider("GDP Shock (%)", -5.0, 5.0, 0.0, 0.1)
unemp_slider = st.slider("Unemployment Shock (pp)", -2.0, 5.0, 0.0, 0.1)
if st.button("Apply Stress"):
    df_stressed = stress_test(df, model, scaler, features, gdp_slider/100, unemp_slider/100)
    new_el = df_stressed['el_stressed'].sum()
    st.metric("Stressed EL", f"${new_el:,.0f}", delta=f"{new_el/total_el - 1:.1%}")

# Individual Loan Lookup
st.subheader("Loan Level Detail")
loan_id = st.number_input("Enter Loan ID", min_value=1, max_value=len(df))
loan = df[df['loan_id'] == loan_id]
if not loan.empty:
    st.write(loan[['loan_id', 'pd', 'el', 'lgd', 'ead', 'default']].iloc[0])
    # SHAP explanation (would need to compute SHAP for the loan)
    st.write("SHAP explanation not shown in this snippet.")

SECTION 5: PROJECT DELIVERABLES CHECKLIST

 
 
Deliverable Description Completed
Code Repository All Python scripts, notebooks, and data. ☐
Data Pipeline Ingestion, cleaning, feature engineering. ☐
Model Trained and validated predictive model. ☐
Risk Calculations PD, LGD, EAD, EL, UL. ☐
Stress Testing Scenario analysis. ☐
Dashboard Interactive Streamlit/Dash app. ☐
Documentation README, project report, and model card. ☐
Presentation 10-minute video or slide deck. ☐

SECTION 6: SUMMARY AND NEXT STEPS

Congratulations! You have completed the Diploma in Financial Data Analytics. You have covered:

  • Module 1: Data landscape, warehousing, SQL, ETL, governance.

  • Module 2: EDA, data preprocessing, feature engineering.

  • Module 3: Probability, statistics, hypothesis testing, MLE, Bayesian methods.

  • Module 4: Machine learning (logistic regression, decision trees, SVM, GBM, deep learning, clustering).

  • Module 5: Financial risk (VaR, GARCH, model validation, credit risk, operational risk, market risk, ALM).

  • Module 6: Advanced topics (NLP, Generative AI, XAI, RL, AI governance, blockchain, quantum).

You are now equipped to:

  • Lead data analytics projects in banking and finance.

  • Build and validate predictive models.

  • Manage financial risk with quantitative methods.

  • Apply cutting-edge AI and emerging technologies.

  • Ensure compliance and ethical use of AI.

Next Steps:

  • Build your portfolio with real-world projects.

  • Pursue certifications (CFA, FRM, or data science certifications).

  • Stay updated with industry trends (AI, blockchain, quantum).

  • Network with professionals in fintech and banking.

  • Consider further studies (MSc in Financial Data Analytics, etc.).

Good luck on your journey!