-
Notifications
You must be signed in to change notification settings - Fork 0
Bussiness Case ‐ European Retail Bank Credit Scoring Card
As a European retail bank, we use a scoring card system to evaluate customer credit applications and determine the associated risk factor. This process helps automate and standardize lending decisions.
This is a test business scenario for demonstration purposes only, but it has a real-world basis as it closely reflects the needs of a retail bank.
The following four factors are used to assess client risk:
- Payment History: This is the most critical factor, indicating a client's past reliability in repaying debts.
- Credit Utilization Ratio: The amount of credit a client is using compared to their total available credit limit. A lower ratio indicates lower risk.
- Length of Credit History: The time the client has managed credit. A longer, positive history generally suggests more experience and stability.
- Employment Stability (Years at Current Employer): A proxy for income stability and the likelihood of the client maintaining their repayment capacity.
This table assigns a rank (score) to each criterion. Higher ranks represent lower risk (more favourable to the bank).
if is younger than 22 yo the Score or this section is negative 10 (-10)
if is over than 65 yo the Score or this section is negative 3 (-3)
| Scoring Factor | Value/Criterion | Rank (Points) if < 45 yo | Rank (Points) if > 45 yo |
|---|---|---|---|
| Payment History | 0 missed payments in the last 24 months | 40 | 30 |
| 1 missed payment in the last 24 months | 25 | 15 | |
| 2 missed payments in the last 24 months | 10 | 7 | |
| 3+ missed payments or major delinquency (e.g., CCJs) | 3 | 0 |
Additional:
| Scoring Factor | Value/Criterion | Rank (Points) |
|---|---|---|
| Credit Utilization Ratio |
|
30 |
| 11% - 30% | 20 | |
| 31% - 50% | 10 | |
|
|
5 | |
| No credit history (i.e., new to credit) | 15 | |
| Length of Credit History | 10+ years | 15 |
| 5 - 9 years | 10 | |
| 2 - 4 years | 5 | |
| < 2 years | 0 | |
| Employment Stability (Years at Current Employer) | 5+ years | 15 |
| 2 - 4 years | 10 | |
| 1 - 2 years | 5 | |
| < 1 year or unemployed | 0 |
The Total Rank is the sum of the ranks for all four factors. This total determines the final lending decision.
| Total Rank Range | Decision | Risk Factor Interpretation |
|---|---|---|
| 0 - 30 | Automatic Reject | Unacceptable risk. High likelihood of default. |
| 31 - 70 | Risk Controller Manual Check | Borderline risk profile. Requires a human risk controller to review specific details and exceptions before a final decision. |
| 71 - 100 | Automatic Approve | Low risk. Meets all primary criteria for immediate approval. |
This sub-program defines the part of the score card with the weights (Rank) for the combination Age and Payment History
In a real case it is very easy to constructed:
- by a service reading a configuration table
- by a diagram that visualize the decision table
- by a business consultant or a business analyst in the current format.
rem Scorecard1: Age, PaymentHistory, Rank
dtrow SCard1, <22, 0, -10 ' PaymentHistory here is irrelevant
dtrow SCard1, 23:45, 0, 40
dtrow SCard1, 23:45, 1, 25
dtrow SCard1, 23:45, 2, 10
dtrow SCard1, 23:45, >=3, 3
dtrow SCard1, 46:65, 0, 30
dtrow SCard1, 46:65, 1, 15
dtrow SCard1, 46:65, 2, 7
dtrow SCard1, 46:65, >=3, 0
dtrow SCard1, >=66,0 , -3 ' PaymentHistory here is irrelevant
REM Scorecard: Credit Utilization Ratio
REM Ratio, Rank
dtrow SCard2, <1, 15 ' also this is the default at DTDIM statement
dtrow SCard2, 1:10, 30
dtrow SCard2, 11:30, 20
dtrow SCard2, 31:50, 10
dtrow SCard2, >50, 5
REM Scorecard: Length of Credit History
REM Years, Rank
dtrow SCard3, >10, 15
dtrow SCard3, 5:9, 10
dtrow SCard3, 2:4, 5
dtrow SCard3, <2, 0
REM Scorecard: Employment Stability (Years at Current Employer)
REM Years, Rank
dtrow SCard4, >=5, 15
dtrow SCard4, 2:4, 10
dtrow SCard4, 1:2, 5
dtrow SCard4, <1, 0
REM Total Rank and Decision Matrix
REM Score, Decision
dtrow Decision, <0, "Automatic Reject"
dtrow Decision, 0:30, "Automatic Reject"
dtrow Decision, 31:70, "Risk Controller Manual Check"
dtrow Decision, 71:100, "Automatic Approve"
dtrow Decision, >101, "Automatic Approve"
This is the main program than getting the use inputs (arguments) and returning the final score
rem Scorecard:
rem
dtdim SCard1, 0, Age, PaymentHistory, Rank
dtdim SCard2, 15, Ratio, Rank
dtdim SCard3, 0, Years, Rank
dtdim SCard4, 0, Years, Rank
dtdim Decision, 0, Score, Decision
' Load the score cards
chain "ScoreCard1.bas"
chain "ScoreCard2.bas"
chain "ScoreCard3.bas"
chain "ScoreCard4.bas"
chain "ScoreDecisionMatrix.bas"
input birthday
input missedPayments
input creditUtilRatio
input yearsOfCreditHistory
input yearsAtEmployer
let age=datediff("YEAR", birthday,date())
LogInfo "Age:"+age
DTFIND SCard1, Rank, score1, age, missedPayments
DTFIND SCard2, Rank, score2, creditUtilRatio
DTFIND SCard3, Rank, score3, yearsOfCreditHistory
dtfind SCard4, Rank, score4, yearsAtEmployer
let score=score1+score2+score3+score4
dtfind Decision, Decision, decisionText, score
result score
This is the scenario orchestration for the business case.
public void Scenario()
{
Console.WriteLine("Business Case 1 - Credit Scoring");
DateTime dateOfBirth = new DateTime(1985, 5, 7);
int missedPayments = 2;
int creditUtilRatio = 60;
int yearsOfCreditHistory = 7;
int yearsAtEmployer = 4;
Console.WriteLine($"Date of Birth : {dateOfBirth:dd/MM/yyyy}");
Console.WriteLine($"Missed Payments : {missedPayments}");
Console.WriteLine($"Credit Utilization Ratio : {creditUtilRatio}");
Console.WriteLine($"Years of Credit History : {yearsOfCreditHistory}");
Console.WriteLine($"Years at current employer: {yearsAtEmployer}");
Console.WriteLine();
(int score,string decision)= Score(dateOfBirth, missedPayments,creditUtilRatio,yearsOfCreditHistory,yearsAtEmployer);
Console.WriteLine($"Score & Decision: {score} : {decision}");
}The scoring method takes as arguments the parameters, and returns the final score
public (int,string) Score(DateTime dateOfBirth,
int missedPayments, int creditUtilRatio,
int yearsOfCreditHistory, int yearsAtEmployer)
{
ArgumentsToInput args = new ArgumentsToInput(dateOfBirth, missedPayments, creditUtilRatio, yearsOfCreditHistory, yearsAtEmployer);
var result = Run("score",args);
var decisionText=result.GetStringVariable("decisionText");
return (result.value.ToInt(), decisionText);
}The class invokes the FBASIC interpreter and contains the Score and Scenario methods. The Scenario method is used only to demonstrate the usage of the Score method. In a real-world scenario, a class like this might serve as the ancestor for all similar score-related methods.
using FAST.FBasicInterpreter;
internal class BusinessCase1
{
private readonly string programsFolder;
public BusinessCase1(string programsFolder)
{
this.programsFolder = programsFolder;
}
// (v) Methods listed in separate block code
// public void Scenario()
// public int Score(DateTime dateOfBirth, int missedPayments )
protected ExecutionResult Run(string programName, ArgumentsToInput args=null)
{
var env= SetupExecutionEnvironment();
if (args != null)
{
env.inputHandler = () => args.GetNextArgumentAsInput();
}
var scoreProgram = File.ReadAllText(Directory.GetFiles(programsFolder, $"{programName}.bas").FirstOrDefault()!);
var interpreter = new Interpreter(env.installBuiltIns, scoreProgram);
env.SetupInterpreter(interpreter);
ExecutionResult result = interpreter.ExecWithResult();
if (result.hasError)
{
throw new Exception($"{result.errorText}\n{result.errorSourceLine}" );
}
return result;
}
protected ExecutionEnvironment SetupExecutionEnvironment()
{
ExecutionEnvironment env= new ExecutionEnvironment();
env.DefaultEnvironment();
env.callHandler = (name) => File.ReadAllText(Path.Combine(this.programsFolder, name));
env.AddLibrary(new FBasicDateFunctions());
env.AddLibrary(new FBasicDecisionTables());
return env;
}