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!