html`
<div style="
display: inline-block;
margin: 0.5rem 0 1rem 0;
padding: 0.75rem 1.25rem;
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
background-color: var(--bs-tertiary-bg);
">
<div style="
font-size: 0.85rem;
color: var(--bs-secondary-color);
">
Principal repayment per period
</div>
<div style="
font-size: 1.5rem;
font-weight: 600;
">
${installmentSchedule.fixedRedemption.toLocaleString(
"en-US",
{
style: "currency",
currency: "EUR"
}
)}
</div>
</div>
`Loan illustrations
Installment loan
viewof installmentLoanAmount = Inputs.range(
[10_000, 250_000],
{
value: 100_000,
step: 5_000,
label: "Principal (€)"
}
)
viewof installmentAnnualRatePercent = Inputs.range(
[0, 15],
{
value: 7,
step: 0.25,
label: "Annual interest rate (%)"
}
)
viewof installmentPaymentPeriods = Inputs.range(
[3, 20],
{
value: 10,
step: 1,
label: "Payment periods"
}
)installmentPlotPeriods = 20
installmentSchedule = {
const interestRate = installmentAnnualRatePercent / 100;
const fixedRedemption =
installmentLoanAmount / installmentPaymentPeriods;
let balance = installmentLoanAmount;
const rows = [];
for (
let period = 1;
period <= installmentPaymentPeriods;
period++
) {
const interest = balance * interestRate;
const redemption = Math.min(fixedRedemption, balance);
rows.push({
period,
component: "Principal repayment",
amount: redemption
});
rows.push({
period,
component: "Interest",
amount: interest
});
balance = Math.max(0, balance - redemption);
}
return {
fixedRedemption,
rows
};
}Plot.plot({
height: 500,
marginLeft: 85,
marginBottom: 55,
x: {
label: "Period",
domain: Array.from(
{length: installmentPlotPeriods},
(_, index) => index + 1
),
tickFormat: period => period
},
y: {
label: "Payment",
grid: true,
tickFormat: value =>
value.toLocaleString("en-US", {
style: "currency",
currency: "EUR",
maximumFractionDigits: 0
})
},
color: {
legend: true,
domain: ["Principal repayment", "Interest"],
range: ["#1f77b4", "#ff7f0e"]
},
marks: [
Plot.barY(
installmentSchedule.rows,
Plot.stackY({
x: "period",
y: "amount",
fill: "component",
title: row =>
`${row.component}: ${row.amount.toLocaleString(
"en-US",
{
style: "currency",
currency: "EUR"
}
)}`
})
),
Plot.ruleY([0])
]
})Annuity loan
viewof loanAmount = Inputs.range(
[10_000, 250_000],
{
value: 100_000,
step: 5_000,
label: "Principal (€)"
}
)
viewof annualRatePercent = Inputs.range(
[0, 15],
{
value: 7,
step: 0.25,
label: "Annual interest rate (%)"
}
)
viewof paymentPeriods = Inputs.range(
[3, 20],
{
value: 10,
step: 1,
label: "Payment periods"
}
)plotPeriods = 20
schedule = {
const interestRate = annualRatePercent / 100;
const annuity =
interestRate === 0
? loanAmount / paymentPeriods
: loanAmount * interestRate /
(1 - (1 + interestRate) ** (-paymentPeriods));
let balance = loanAmount;
const rows = [];
for (let period = 1; period <= paymentPeriods; period++) {
const interest = balance * interestRate;
const redemption = Math.min(annuity - interest, balance);
rows.push({
period,
component: "Principal repayment",
amount: redemption
});
rows.push({
period,
component: "Interest",
amount: interest
});
balance = Math.max(0, balance - redemption);
}
return {annuity, rows};
}html`
<div style="
display: inline-block;
margin: 0.5rem 0 1rem 0;
padding: 0.75rem 1.25rem;
border: 1px solid var(--bs-border-color);
border-radius: 0.5rem;
background-color: var(--bs-tertiary-bg);
">
<div style="
font-size: 0.85rem;
color: var(--bs-secondary-color);
">
Annual payment
</div>
<div style="
font-size: 1.5rem;
font-weight: 600;
">
${schedule.annuity.toLocaleString("en-US", {
style: "currency",
currency: "EUR"
})}
</div>
</div>
`Plot.plot({
height: 500,
marginLeft: 85,
marginBottom: 55,
x: {
label: "Period",
domain: Array.from(
{length: plotPeriods},
(_, index) => index + 1
),
tickFormat: period => period
},
y: {
label: "Annual payment",
grid: true,
tickFormat: value =>
value.toLocaleString("en-US", {
style: "currency",
currency: "EUR",
maximumFractionDigits: 0
})
},
color: {
legend: true,
domain: ["Principal repayment", "Interest"],
range: ["#1f77b4", "#ff7f0e"]
},
marks: [
Plot.barY(
schedule.rows,
Plot.stackY({
x: "period",
y: "amount",
fill: "component",
title: row =>
`${row.component}: ${
row.amount.toLocaleString("en-US", {
style: "currency",
currency: "EUR"
})
}`
})
),
Plot.ruleY([0])
]
})