Skip to content

Commit aafd32b

Browse files
committed
repo
1 parent fe56d7e commit aafd32b

54 files changed

Lines changed: 10436 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Banking Data Pipeline — Credit Risk (ETL)
2+
3+
## Overview
4+
This repository contains a compact, production‑style ETL pipeline for calculating **Risk‑Weighted Assets (RWA)** using standard Credit Risk parameters:
5+
6+
- **EAD** — Exposure at Default
7+
- **PD** — Probability of Default
8+
- **LGD** — Loss Given Default
9+
10+
The pipeline mirrors the type of operational data processing performed within **BNP Paribas Finance & Risk Solutions**.
11+
12+
The core Basel‑style formula implemented is:
13+
14+
\[
15+
RWA = EAD \times PD \times LGD \times 12.5
16+
\]
17+
18+
---
19+
20+
## 🔍 Business Logic Highlights
21+
22+
### **Data Quality**
23+
- Negative exposures are automatically filtered out.
24+
- All transformations are logged for traceability.
25+
26+
### **Operational Reliability**
27+
- Extraction failures (e.g., missing files) raise clear, support‑friendly errors.
28+
- Logging provides a full audit trail of ETL steps.
29+
30+
### **Database Layer**
31+
- Results are written to SQLite for demo purposes.
32+
- `db_setup.sql` includes indexing to support large‑scale reporting workloads.
33+
34+
---
35+
36+
## 🚀 How to Run the Pipeline
37+
38+
### **1. Install the package (editable mode recommended during development)**
39+
40+
From the project root:
41+
42+
```bash
43+
pip install -e banking_data_pipeline_python
44+
```
45+
46+
This makes the `banking_data_pipeline` package importable from anywhere.
47+
48+
---
49+
50+
### **2. Run the ETL pipeline**
51+
52+
Because the project is now a proper Python package, you run it using the module syntax:
53+
54+
```bash
55+
python -m banking_data_pipeline.rwa_calculator
56+
```
57+
58+
This works from **any directory**, thanks to the `pathlib`‑based data resolution inside the script.
59+
60+
---
61+
62+
## Running Tests
63+
64+
Tests are located under:
65+
66+
```
67+
banking_data_pipeline_python/tests/
68+
```
69+
70+
Run them with:
71+
72+
```bash
73+
pytest
74+
```
75+
76+
All tests validate:
77+
78+
- RWA calculation correctness
79+
- Negative exposure filtering
80+
- Error handling for missing files
81+
82+
---
83+
84+
## Project Structure
85+
86+
```
87+
bnp/
88+
89+
├── banking_data_pipeline_python/
90+
│ ├── banking_data_pipeline/
91+
│ │ ├── rwa_calculator.py
92+
│ │ ├── data/
93+
│ │ │ └── mock_loans.csv
94+
│ │ └── __init__.py
95+
│ └── tests/
96+
│ └── test_rwa_calculator.py
97+
98+
└── pyproject.toml
99+
```
100+
101+
---
102+
103+
## 🛠️ Tech Stack
104+
105+
- **Python 3.11**
106+
- **NumPy 1.26.4**
107+
- **Pandas 2.1.4**
108+
- **SQLite**
109+
- **Pytest**
110+
111+
All versions are pinned in `pyproject.toml` for reproducibility.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Metadata-Version: 2.4
2+
Name: banking-data-pipeline
3+
Version: 0.1.0
4+
Requires-Dist: numpy==1.26.4
5+
Requires-Dist: pandas==2.1.4
6+
Requires-Dist: pytest==9.0.2
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
README.md
2+
pyproject.toml
3+
requirements.txt
4+
banking_data_pipeline/__init__.py
5+
banking_data_pipeline/rwa_calculator.py
6+
banking_data_pipeline.egg-info/PKG-INFO
7+
banking_data_pipeline.egg-info/SOURCES.txt
8+
banking_data_pipeline.egg-info/dependency_links.txt
9+
banking_data_pipeline.egg-info/requires.txt
10+
banking_data_pipeline.egg-info/top_level.txt
11+
tests/test_rwa_calculator.py
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
numpy==1.26.4
2+
pandas==2.1.4
3+
pytest==9.0.2
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
banking_data_pipeline

banking_data_pipeline_python/banking_data_pipeline/__init__.py

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import logging
2+
import os
3+
import sqlite3
4+
from pathlib import Path
5+
6+
import pandas as pd
7+
from pandas import DataFrame
8+
9+
logging.basicConfig(
10+
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
11+
)
12+
13+
14+
class CreditRiskETL:
15+
def __init__(self, db_name: str = "banking_risk.db"):
16+
self.db_name = db_name
17+
18+
def extract(self, file_path: str) -> DataFrame:
19+
logging.info(f"Extracting data from {file_path}")
20+
if not os.path.exists(file_path):
21+
raise FileNotFoundError(f"Source file {file_path} missing.")
22+
return pd.read_csv(file_path)
23+
24+
def transform(self, df: DataFrame) -> DataFrame:
25+
logging.info("Starting transformation: Calculating RWA")
26+
27+
# 1. Data Cleaning: Remove invalid exposure
28+
valid_df = df[df["exposure_at_default"] > 0].copy()
29+
dropped = len(df) - len(valid_df)
30+
if dropped > 0:
31+
logging.warning(f"Dropped {dropped} rows with invalid exposure values.")
32+
33+
# 2. RWA Calculation: RWA = EAD * PD * LGD * 12.5
34+
# Using 12.5 as the standard Basel multiplier for demo purposes
35+
valid_df["rwa"] = (
36+
valid_df["exposure_at_default"]
37+
* valid_df["probability_of_default"]
38+
* valid_df["loss_given_default"]
39+
* 12.5
40+
)
41+
42+
return valid_df
43+
44+
def load(self, df: DataFrame) -> None:
45+
logging.info(f"Loading {len(df)} records to database {self.db_name}")
46+
conn = sqlite3.connect(self.db_name)
47+
48+
# Mapping DataFrame columns to SQL table
49+
df.to_sql("risk_reports", conn, if_exists="append", index=False)
50+
conn.close()
51+
logging.info("Load complete.")
52+
53+
54+
if __name__ == "__main__":
55+
PACKAGE_ROOT = Path(__file__).resolve().parent
56+
DATA_FILE = PACKAGE_ROOT / "data" / "mock_loans.csv"
57+
58+
etl = CreditRiskETL()
59+
try:
60+
raw_data = etl.extract(str(DATA_FILE))
61+
processed_data = etl.transform(raw_data)
62+
etl.load(processed_data)
63+
except Exception as e:
64+
logging.error(f"Pipeline Failed: {e}")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
loan_id,customer_name,exposure_at_default,probability_of_default,loss_given_default,sector
2+
L001,Global Tech Corp,1500000.00,0.02,0.45,Technology
3+
L002,Main Street Retail,500000.00,0.08,0.35,Retail
4+
L003,BioHealth Inc,2200000.00,0.01,0.40,Healthcare
5+
L004,BuildIt Construction,850000.00,0.12,0.50,Construction
6+
L005,Invalid Data Co,-100.00,0.05,0.40,Finance
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[build-system]
2+
requires = ["setuptools"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "banking-data-pipeline"
7+
version = "0.1.0"
8+
dependencies = [
9+
"numpy==1.26.4",
10+
"pandas==2.1.4",
11+
"pytest==9.0.2"
12+
]
13+
14+
[tool.setuptools]
15+
packages = ["banking_data_pipeline"]
16+
17+
[tool.pytest.ini_options]
18+
pythonpath = ["."]

0 commit comments

Comments
 (0)