Payment Schedule Examples
Basic example #1
The following example shows the scheduled for a car loan of £10,000 taken out on 7 February 2024 with 36 monthly repayments:
#r "nuget:FSharp.Finance.Personal"
open FSharp.Finance.Personal
open Calculation
open DateDay
open Scheduling
let scheduleParameters =
{
AsOfDate = Date(2024, 02, 07)
StartDate = Date(2024, 02, 07)
Principal = 10000_00L<Cent>
ScheduleConfig = AutoGenerateSchedule {
UnitPeriodConfig = UnitPeriod.Monthly(1, 2024, 3, 7)
PaymentCount = 36
MaxDuration = Duration.Unlimited
}
PaymentConfig = {
ScheduledPaymentOption = AsScheduled
CloseBalanceOption = LeaveOpenBalance
PaymentRounding = RoundUp
MinimumPayment = DeferOrWriteOff 50L<Cent>
PaymentTimeout = 3<DurationDay>
}
FeeConfig = Fee.Config.initialRecommended
ChargeConfig = Charge.Config.initialRecommended
InterestConfig = {
Method = Interest.Method.Simple
StandardRate = Interest.Rate.Annual (Percent 6.9m)
Cap = Interest.Cap.zero
InitialGracePeriod = 0<DurationDay>
PromotionalRates = [||]
RateOnNegativeBalance = Interest.Rate.Zero
AprMethod = Apr.CalculationMethod.UnitedKingdom 3
InterestRounding = RoundDown
}
}
let schedule = scheduleParameters |> calculate AroundZero
schedule
|
It is possible to format the Items
property as an HTML table:
let html = schedule.Items |> Formatting.generateHtmlFromArray [||]
$"""<div style="overflow-x: auto;">{html}</div>"""
Day | Scheduled Payment | Simple Interest | Interest Portion | Principal Portion | Interest Balance | Principal Balance | Total Simple Interest | Total Interest | Total Principal |
---|---|---|---|---|---|---|---|---|---|
0 | 0.00 | 0.00 | 0.00 | 0.00 | 10,000.00 | 0.00 | 0.00 | 0.00 | |
29 | original 308.29 | 54.82 | 54.82 | 253.47 | 0.00 | 9,746.53 | 54.82 | 54.82 | 253.47 |
60 | original 308.29 | 57.11 | 57.11 | 251.18 | 0.00 | 9,495.35 | 111.93 | 111.93 | 504.65 |
90 | original 308.29 | 53.85 | 53.85 | 254.44 | 0.00 | 9,240.91 | 165.78 | 165.78 | 759.09 |
121 | original 308.29 | 54.15 | 54.15 | 254.14 | 0.00 | 8,986.77 | 219.93 | 219.93 | 1,013.23 |
151 | original 308.29 | 50.96 | 50.96 | 257.33 | 0.00 | 8,729.44 | 270.89 | 270.89 | 1,270.56 |
182 | original 308.29 | 51.15 | 51.15 | 257.14 | 0.00 | 8,472.30 | 322.04 | 322.04 | 1,527.70 |
213 | original 308.29 | 49.64 | 49.64 | 258.65 | 0.00 | 8,213.65 | 371.68 | 371.68 | 1,786.35 |
243 | original 308.29 | 46.58 | 46.58 | 261.71 | 0.00 | 7,951.94 | 418.26 | 418.26 | 2,048.06 |
274 | original 308.29 | 46.60 | 46.60 | 261.69 | 0.00 | 7,690.25 | 464.86 | 464.86 | 2,309.75 |
304 | original 308.29 | 43.61 | 43.61 | 264.68 | 0.00 | 7,425.57 | 508.47 | 508.47 | 2,574.43 |
335 | original 308.29 | 43.51 | 43.51 | 264.78 | 0.00 | 7,160.79 | 551.98 | 551.98 | 2,839.21 |
366 | original 308.29 | 41.96 | 41.96 | 266.33 | 0.00 | 6,894.46 | 593.94 | 593.94 | 3,105.54 |
394 | original 308.29 | 36.49 | 36.49 | 271.80 | 0.00 | 6,622.66 | 630.43 | 630.43 | 3,377.34 |
425 | original 308.29 | 38.81 | 38.81 | 269.48 | 0.00 | 6,353.18 | 669.24 | 669.24 | 3,646.82 |
455 | original 308.29 | 36.03 | 36.03 | 272.26 | 0.00 | 6,080.92 | 705.27 | 705.27 | 3,919.08 |
486 | original 308.29 | 35.63 | 35.63 | 272.66 | 0.00 | 5,808.26 | 740.90 | 740.90 | 4,191.74 |
516 | original 308.29 | 32.93 | 32.93 | 275.36 | 0.00 | 5,532.90 | 773.83 | 773.83 | 4,467.10 |
547 | original 308.29 | 32.42 | 32.42 | 275.87 | 0.00 | 5,257.03 | 806.25 | 806.25 | 4,742.97 |
578 | original 308.29 | 30.80 | 30.80 | 277.49 | 0.00 | 4,979.54 | 837.05 | 837.05 | 5,020.46 |
608 | original 308.29 | 28.24 | 28.24 | 280.05 | 0.00 | 4,699.49 | 865.29 | 865.29 | 5,300.51 |
639 | original 308.29 | 27.54 | 27.54 | 280.75 | 0.00 | 4,418.74 | 892.83 | 892.83 | 5,581.26 |
669 | original 308.29 | 25.05 | 25.05 | 283.24 | 0.00 | 4,135.50 | 917.88 | 917.88 | 5,864.50 |
700 | original 308.29 | 24.23 | 24.23 | 284.06 | 0.00 | 3,851.44 | 942.11 | 942.11 | 6,148.56 |
731 | original 308.29 | 22.57 | 22.57 | 285.72 | 0.00 | 3,565.72 | 964.68 | 964.68 | 6,434.28 |
759 | original 308.29 | 18.87 | 18.87 | 289.42 | 0.00 | 3,276.30 | 983.55 | 983.55 | 6,723.70 |
790 | original 308.29 | 19.20 | 19.20 | 289.09 | 0.00 | 2,987.21 | 1,002.75 | 1,002.75 | 7,012.79 |
820 | original 308.29 | 16.94 | 16.94 | 291.35 | 0.00 | 2,695.86 | 1,019.69 | 1,019.69 | 7,304.14 |
851 | original 308.29 | 15.79 | 15.79 | 292.50 | 0.00 | 2,403.36 | 1,035.48 | 1,035.48 | 7,596.64 |
881 | original 308.29 | 13.63 | 13.63 | 294.66 | 0.00 | 2,108.70 | 1,049.11 | 1,049.11 | 7,891.30 |
912 | original 308.29 | 12.35 | 12.35 | 295.94 | 0.00 | 1,812.76 | 1,061.46 | 1,061.46 | 8,187.24 |
943 | original 308.29 | 10.62 | 10.62 | 297.67 | 0.00 | 1,515.09 | 1,072.08 | 1,072.08 | 8,484.91 |
973 | original 308.29 | 8.59 | 8.59 | 299.70 | 0.00 | 1,215.39 | 1,080.67 | 1,080.67 | 8,784.61 |
1004 | original 308.29 | 7.12 | 7.12 | 301.17 | 0.00 | 914.22 | 1,087.79 | 1,087.79 | 9,085.78 |
1034 | original 308.29 | 5.18 | 5.18 | 303.11 | 0.00 | 611.11 | 1,092.97 | 1,092.97 | 9,388.89 |
1065 | original 308.29 | 3.58 | 3.58 | 304.71 | 0.00 | 306.40 | 1,096.55 | 1,096.55 | 9,693.60 |
1096 | original 308.19 | 1.79 | 1.79 | 306.40 | 0.00 | 0.00 | 1,098.34 | 1,098.34 | 10,000.00 |
Multiple items
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp.Finance
namespace FSharp.Finance.Personal
module Calculation
from FSharp.Finance.Personal
<summary> convenience functions and options to help with calculations </summary>
<summary> convenience functions and options to help with calculations </summary>
module DateDay
from FSharp.Finance.Personal
<summary> a .NET Framework polyfill equivalent to the DateOnly structure in .NET Core </summary>
<summary> a .NET Framework polyfill equivalent to the DateOnly structure in .NET Core </summary>
module Scheduling
from FSharp.Finance.Personal
<summary> functions for generating a regular payment schedule, with payment amounts, interest and APR </summary>
<summary> functions for generating a regular payment schedule, with payment amounts, interest and APR </summary>
val scheduleParameters: Parameters
Multiple items
[<Struct>] type Date = new: year: int * month: int * day: int -> Date val Year: int val Month: int val Day: int member AddDays: i: int -> Date member AddMonths: i: int -> Date member AddYears: i: int -> Date member ToDateTime: unit -> DateTime override ToString: unit -> string static member (-) : d1: Date * d2: Date -> TimeSpan ...
<summary> the date at the customer's location - ensure any time-zone conversion is performed before using this - as all calculations are date-only with no time component, summer time or other such time artefacts </summary>
--------------------
Date ()
new: year: int * month: int * day: int -> Date
[<Struct>] type Date = new: year: int * month: int * day: int -> Date val Year: int val Month: int val Day: int member AddDays: i: int -> Date member AddMonths: i: int -> Date member AddYears: i: int -> Date member ToDateTime: unit -> DateTime override ToString: unit -> string static member (-) : d1: Date * d2: Date -> TimeSpan ...
<summary> the date at the customer's location - ensure any time-zone conversion is performed before using this - as all calculations are date-only with no time component, summer time or other such time artefacts </summary>
--------------------
Date ()
new: year: int * month: int * day: int -> Date
Multiple items
module Cent from FSharp.Finance.Personal.Calculation
<summary> utility functions for base currency unit values </summary>
--------------------
[<Measure>] type Cent
<summary> the base unit of a currency (cent, penny, øre etc.) </summary>
module Cent from FSharp.Finance.Personal.Calculation
<summary> utility functions for base currency unit values </summary>
--------------------
[<Measure>] type Cent
<summary> the base unit of a currency (cent, penny, øre etc.) </summary>
[<Struct>]
type ScheduleConfig =
| AutoGenerateSchedule of AutoGenerateSchedule: AutoGenerateSchedule
| FixedSchedules of FixedSchedules: FixedSchedule array
| CustomSchedule of CustomSchedule: Map<int<OffsetDay>,ScheduledPayment>
<summary> whether a payment plan is generated according to a regular schedule or is an irregular array of payments </summary>
<summary> whether a payment plan is generated according to a regular schedule or is an irregular array of payments </summary>
Multiple items
union case ScheduleConfig.AutoGenerateSchedule: AutoGenerateSchedule: AutoGenerateSchedule -> ScheduleConfig
<summary> a schedule based on a unit-period config with a specific number of payments with an auto-calculated amount, optionally limited to a maximum duration </summary>
--------------------
[<Struct>] type AutoGenerateSchedule = { UnitPeriodConfig: Config PaymentCount: int MaxDuration: Duration }
<summary> a regular schedule based on a unit-period config with a specific number of payments with an auto-calculated amount </summary>
union case ScheduleConfig.AutoGenerateSchedule: AutoGenerateSchedule: AutoGenerateSchedule -> ScheduleConfig
<summary> a schedule based on a unit-period config with a specific number of payments with an auto-calculated amount, optionally limited to a maximum duration </summary>
--------------------
[<Struct>] type AutoGenerateSchedule = { UnitPeriodConfig: Config PaymentCount: int MaxDuration: Duration }
<summary> a regular schedule based on a unit-period config with a specific number of payments with an auto-calculated amount </summary>
module UnitPeriod
from FSharp.Finance.Personal
<summary> an unambiguous way to represent regular date intervals and generate schedules based on them note: unit-period definitions are based on US federal legislation but the definitions are universally applicable </summary>
<summary> an unambiguous way to represent regular date intervals and generate schedules based on them note: unit-period definitions are based on US federal legislation but the definitions are universally applicable </summary>
union case UnitPeriod.Config.Monthly: MonthMultiple: int * Year: int * Month: int * Day: int -> UnitPeriod.Config
<summary> (multi-)monthly: every n months starting on the date given by year, month and day, which tracks month-end (see config) </summary>
<summary> (multi-)monthly: every n months starting on the date given by year, month and day, which tracks month-end (see config) </summary>
[<Struct>]
type Duration =
| Unlimited
| Maximum of Length: int<DurationDay> * FromDate: Date
<summary> a length of time in whole days measured from a start date </summary>
<summary> a length of time in whole days measured from a start date </summary>
union case Duration.Unlimited: Duration
<summary> unrestricted length of time </summary>
<summary> unrestricted length of time </summary>
type PaymentConfig =
{
ScheduledPaymentOption: ScheduledPaymentOption
CloseBalanceOption: CloseBalanceOption
PaymentRounding: Rounding
MinimumPayment: MinimumPayment
PaymentTimeout: int<DurationDay>
}
<summary> how to treat scheduled payments </summary>
<summary> how to treat scheduled payments </summary>
[<Struct>]
type ScheduledPaymentOption =
| AsScheduled
| AddChargesAndInterest
<summary> whether to stick to scheduled payment amounts or add charges and interest to them </summary>
<summary> whether to stick to scheduled payment amounts or add charges and interest to them </summary>
union case ScheduledPaymentOption.AsScheduled: ScheduledPaymentOption
<summary> keep to the scheduled payment amounts even if this results in an open balance </summary>
<summary> keep to the scheduled payment amounts even if this results in an open balance </summary>
[<Struct>]
type CloseBalanceOption =
| LeaveOpenBalance
| IncreaseFinalPayment
| AddSingleExtraPayment
| AddMultipleExtraPayments
<summary> how to handle a final balance if not closed: leave it open or modify/add payments at the end of the schedule </summary>
<summary> how to handle a final balance if not closed: leave it open or modify/add payments at the end of the schedule </summary>
union case CloseBalanceOption.LeaveOpenBalance: CloseBalanceOption
<summary> do not modify the final payment and leave any open balance as is </summary>
<summary> do not modify the final payment and leave any open balance as is </summary>
union case Rounding.RoundUp: Rounding
<summary> round up to the specified precision (= ceiling) </summary>
<summary> round up to the specified precision (= ceiling) </summary>
[<Struct>]
type MinimumPayment =
| NoMinimumPayment
| DeferOrWriteOff of DeferOrWriteOff: int64<Cent>
| ApplyMinimumPayment of ApplyMinimumPayment: int64<Cent>
<summary> how to handle cases where the payment due is less than the minimum that payment providers can process </summary>
<summary> how to handle cases where the payment due is less than the minimum that payment providers can process </summary>
union case MinimumPayment.DeferOrWriteOff: DeferOrWriteOff: int64<Cent> -> MinimumPayment
<summary> add the payment due to the next payment or close the balance if the final payment </summary>
<summary> add the payment due to the next payment or close the balance if the final payment </summary>
[<Measure>]
type DurationDay
<summary> a duration of a number of days </summary>
<summary> a duration of a number of days </summary>
module Fee
from FSharp.Finance.Personal
<summary> a product fee > NOTE: differences between fees and charges: > - fees are up-front amounts paid under agreed terms for receiving an advance > - fees are added to the principal balance and therefore accrue interest </summary>
<summary> a product fee > NOTE: differences between fees and charges: > - fees are up-front amounts paid under agreed terms for receiving an advance > - fees are added to the principal balance and therefore accrue interest </summary>
Multiple items
module Config from FSharp.Finance.Personal.Fee
<summary> options specifying the types of fees, their amounts, and any restrictions on these </summary>
--------------------
type Config = { FeeTypes: FeeType array Rounding: Rounding FeeAmortisation: FeeAmortisation SettlementRefund: SettlementRefund }
<summary> options specifying the types of fees, their amounts, and any restrictions on these </summary>
module Config from FSharp.Finance.Personal.Fee
<summary> options specifying the types of fees, their amounts, and any restrictions on these </summary>
--------------------
type Config = { FeeTypes: FeeType array Rounding: Rounding FeeAmortisation: FeeAmortisation SettlementRefund: SettlementRefund }
<summary> options specifying the types of fees, their amounts, and any restrictions on these </summary>
val initialRecommended: Fee.Config
<summary> a default config value, with no fees but recommended settings </summary>
<summary> a default config value, with no fees but recommended settings </summary>
module Charge
from FSharp.Finance.Personal
<summary> a penalty charge > NB: differences between charges and fees: > - charges are not up-front amounts, they are incurred as a result of a breach of agreed terms > - charges are not added to the principal balance and do not therefore accrue interest </summary>
<summary> a penalty charge > NB: differences between charges and fees: > - charges are not up-front amounts, they are incurred as a result of a breach of agreed terms > - charges are not added to the principal balance and do not therefore accrue interest </summary>
Multiple items
module Config from FSharp.Finance.Personal.Charge
<summary> options specifying the types of charges, their amounts, and any restrictions on these </summary>
--------------------
type Config = { ChargeTypes: ChargeType array Rounding: Rounding ChargeHolidays: DateRange array ChargeGrouping: ChargeGrouping LatePaymentGracePeriod: int<DurationDay> }
<summary> options specifying the types of charges, their amounts, and any restrictions on these </summary>
module Config from FSharp.Finance.Personal.Charge
<summary> options specifying the types of charges, their amounts, and any restrictions on these </summary>
--------------------
type Config = { ChargeTypes: ChargeType array Rounding: Rounding ChargeHolidays: DateRange array ChargeGrouping: ChargeGrouping LatePaymentGracePeriod: int<DurationDay> }
<summary> options specifying the types of charges, their amounts, and any restrictions on these </summary>
val initialRecommended: Charge.Config
<summary> a default config value, with no charges but recommended settings </summary>
<summary> a default config value, with no charges but recommended settings </summary>
module Interest
from FSharp.Finance.Personal
<summary> methods for calculating interest and unambiguously expressing interest rates, as well as enforcing regulatory caps on interest chargeable </summary>
<summary> methods for calculating interest and unambiguously expressing interest rates, as well as enforcing regulatory caps on interest chargeable </summary>
[<Struct>]
type Method =
| Simple
| AddOn
<summary> the method used to calculate the interest </summary>
<summary> the method used to calculate the interest </summary>
union case Interest.Method.Simple: Interest.Method
<summary> simple interest method, where interest is based on the principal balance and the number of days outstanding </summary>
<summary> simple interest method, where interest is based on the principal balance and the number of days outstanding </summary>
Multiple items
module Rate from FSharp.Finance.Personal.Interest
--------------------
[<Struct>] type Rate = | Zero | Annual of Annual: Percent | Daily of Daily: Percent
<summary> the interest rate expressed as either an annual or a daily rate </summary>
module Rate from FSharp.Finance.Personal.Interest
--------------------
[<Struct>] type Rate = | Zero | Annual of Annual: Percent | Daily of Daily: Percent
<summary> the interest rate expressed as either an annual or a daily rate </summary>
union case Interest.Rate.Annual: Annual: Percent -> Interest.Rate
<summary> the annual interest rate, or the daily interest rate multiplied by 365 </summary>
<summary> the annual interest rate, or the daily interest rate multiplied by 365 </summary>
Multiple items
union case Percent.Percent: decimal -> Percent
--------------------
module Percent from FSharp.Finance.Personal.Calculation
<summary> utility functions for percent values </summary>
--------------------
type Percent = | Percent of decimal
<summary> a percentage, e.g. 42%, as opposed to its decimal representation 0.42m </summary>
union case Percent.Percent: decimal -> Percent
--------------------
module Percent from FSharp.Finance.Personal.Calculation
<summary> utility functions for percent values </summary>
--------------------
type Percent = | Percent of decimal
<summary> a percentage, e.g. 42%, as opposed to its decimal representation 0.42m </summary>
Multiple items
module Cap from FSharp.Finance.Personal.Interest
<summary> caps on the total interest accruable </summary>
--------------------
[<Struct>] type Cap = { TotalAmount: Amount voption DailyAmount: Amount voption }
<summary> caps on the total interest accruable </summary>
module Cap from FSharp.Finance.Personal.Interest
<summary> caps on the total interest accruable </summary>
--------------------
[<Struct>] type Cap = { TotalAmount: Amount voption DailyAmount: Amount voption }
<summary> caps on the total interest accruable </summary>
val zero: Interest.Cap
<summary> no cap </summary>
<summary> no cap </summary>
union case Interest.Rate.Zero: Interest.Rate
<summary> a zero rate </summary>
<summary> a zero rate </summary>
module Apr
from FSharp.Finance.Personal
<summary> calculating the APR according to various country-specific regulations </summary>
<summary> calculating the APR according to various country-specific regulations </summary>
[<Struct>]
type CalculationMethod =
| UnitedKingdom of UkPrecision: int
| UsActuarial of UsPrecision: int
| UnitedStatesRule
<summary> the calculation method used to determine the APR </summary>
<summary> the calculation method used to determine the APR </summary>
union case Apr.CalculationMethod.UnitedKingdom: UkPrecision: int -> Apr.CalculationMethod
<summary> calculates the APR according to UK FCA rules to the stated decimal precision (note that this is two places more than the percent precision) </summary>
<summary> calculates the APR according to UK FCA rules to the stated decimal precision (note that this is two places more than the percent precision) </summary>
union case Rounding.RoundDown: Rounding
<summary> round down to the specified precision (= floor) </summary>
<summary> round down to the specified precision (= floor) </summary>
val schedule: SimpleSchedule
val calculate: toleranceOption: TargetTolerance -> sp: Parameters -> SimpleSchedule
<summary> calculates the number of days between two offset days on which interest is chargeable </summary>
<summary> calculates the number of days between two offset days on which interest is chargeable </summary>
union case TargetTolerance.AroundZero: TargetTolerance
<summary> find a solution either side of zero </summary>
<summary> find a solution either side of zero </summary>
val html: string
SimpleSchedule.Items: SimpleItem array
<summary> the items of the schedule </summary>
<summary> the items of the schedule </summary>
module Formatting
from FSharp.Finance.Personal
<summary> convenience module for generating HTML tables, optimised for amortisation schedules </summary>
<summary> convenience module for generating HTML tables, optimised for amortisation schedules </summary>
val generateHtmlFromArray: hideProperties: string array -> items: 'a array -> string
<summary> generates a formatted HTML table from an array </summary>
<summary> generates a formatted HTML table from an array </summary>