US APR calculation
Basic example
The following example shows a loan of $5,000.00 taken out on 10th January 1978 and repaid in 24 monthly instalments:
#r "nuget:FSharp.Finance.Personal"
open FSharp.Finance.Personal
open Apr
open Calculation
open DateDay
open UnitPeriod
let startDate = Date(1978, 1, 10)
let principal = 5000_00L<Cent>
let transfers =
Monthly (1, 1978, 2, 10)
|> generatePaymentSchedule 24 Duration.Unlimited Direction.Forward
|> Array.map(fun d -> { TransferType = Payment; TransferDate = d; Value = 230_00L<Cent> })
let aprMethod = CalculationMethod.UsActuarial 4
let solution = Apr.calculate aprMethod principal startDate transfers
solution
|
This result is of an Array.Solution
type. Found
means that it was able to find a solution.
The APR, expressed as a decimal, is returned as the first item of the tuple. The APR is more usefully shown as a percentage,
which can easily be done as follows:
solution |> toPercent aprMethod
|
Notes
- The current implementation only supports single-advance transactions
- The solver tries to find a solution that stabilises at 10 decimal places, using no more than 100 iterations
-
If it cannot find a solution within these confines, it will return
IterationLimitReached
along with a tuple giving the partial solution as the first item (which may or may not be a good approximation of the answer) - If the transfers list is empty, it will return
Solution.Impossible
- The remaining parts of the solution tuples return information about the number of iterations used and details of any tolerances configured. However, these are currently not customisable for US APR calculations so are not useful here.
Multiple items
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp.Finance
namespace FSharp.Finance.Personal
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>
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 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>
val startDate: Date
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
val principal: int64<Cent>
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>
val transfers: Transfer array
union case Config.Monthly: MonthMultiple: int * Year: int * Month: int * Day: int -> 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>
val generatePaymentSchedule: count: int -> maxDuration: Duration -> direction: Direction -> unitPeriodConfig: Config -> Date array
<summary> generate a payment schedule based on a unit-period config </summary>
<summary> generate a payment schedule based on a unit-period 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>
[<Struct>]
type Direction =
| Forward
| Reverse
<summary> direction in which to generate the schedule: forward works forwards from a given date and reverse works backwards </summary>
<summary> direction in which to generate the schedule: forward works forwards from a given date and reverse works backwards </summary>
union case Direction.Forward: Direction
<summary> create a schedule starting on the given date </summary>
<summary> create a schedule starting on the given date </summary>
Multiple items
module Array from FSharp.Finance.Personal.Calculation
<summary> functions for working with arrays </summary>
--------------------
module Array from Microsoft.FSharp.Collections
module Array from FSharp.Finance.Personal.Calculation
<summary> functions for working with arrays </summary>
--------------------
module Array from Microsoft.FSharp.Collections
val map: mapping: ('T -> 'U) -> array: 'T array -> 'U array
val d: Date
[<Struct>]
type TransferType =
| Advance
| Payment
<summary> whether a transfer is an advance or a payment </summary>
<summary> whether a transfer is an advance or a payment </summary>
union case TransferType.Payment: TransferType
<summary> incoming transfer </summary>
<summary> incoming transfer </summary>
val aprMethod: CalculationMethod
[<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 CalculationMethod.UsActuarial: UsPrecision: int -> CalculationMethod
<summary> calculates the APR according to the US CFPB actuarial method to the stated decimal precision (note that this is two places more than the percent precision) </summary>
<summary> calculates the APR according to the US CFPB actuarial method to the stated decimal precision (note that this is two places more than the percent precision) </summary>
val solution: Solution
val calculate: method: CalculationMethod -> advanceValue: int64<Cent> -> advanceDate: Date -> transfers: Transfer array -> Solution
<summary> calculates the APR to a given precision for a single-advance transaction where the consummation date, first finance-charge earned date and advance date are all the same </summary>
<summary> calculates the APR to a given precision for a single-advance transaction where the consummation date, first finance-charge earned date and advance date are all the same </summary>
val toPercent: aprMethod: CalculationMethod -> aprSolution: Solution -> Percent voption
<summary> converts an APR solution to a percentage, if possible </summary>
<summary> converts an APR solution to a percentage, if possible </summary>