FinanceCore API Reference
FinanceCore.AbstractContractFinanceCore.CashflowFinanceCore.CompositeFinanceCore.ContinuousFinanceCore.ContinuousFinanceCore.FrequencyFinanceCore.PeriodicFinanceCore.PeriodicFinanceCore.QuoteFinanceCore.RateFinanceCore.TimepointFinanceCore.accumulationFinanceCore.accumulationFinanceCore.aggregateFinanceCore.amountFinanceCore.compoundingFinanceCore.discountFinanceCore.discountFinanceCore.discountFinanceCore.discountFinanceCore.discountFinanceCore.forwardFinanceCore.forwardFinanceCore.internal_rate_of_returnFinanceCore.internal_rate_of_returnFinanceCore.irrFinanceCore.maturityFinanceCore.present_valueFinanceCore.present_valueFinanceCore.rateFinanceCore.timepoint
Exported API
FinanceCore.Cashflow — Type
Cashflow(amount,time)A Cashflow{A,B} is a contract that pays an amount at time.
Cashflows can be:
- negated with the unary
-operator. - added or subtracted when their times are exactly equal (
==). To combine cashflows at different times, useFinanceCore.aggregate. - multiplied/divided by a scalar.
Supertype Hierarchy ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
Cashflow{A<:Real, B<:Timepoint} <: FinanceCore.AbstractContract <: AnyFinanceCore.Composite — Type
Composite(A,B)Summary ≡≡≡≡≡≡≡≡≡
struct Composite{A, B}A Composite{A,B} is a contract that is composed of two other contracts of type A and type B. The maturity of the composite is the maximum of the maturities of the two components.
It is used to assemble arbitrarily complex contracts from simpler ones.
Fields ≡≡≡≡≡≡≡≡
a :: A
b :: BSupertype Hierarchy ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
Composite{A, B} <: FinanceCore.AbstractContract <: AnyFinanceCore.Continuous — Type
Continuous()A type representing continuous interest compounding frequency.
Use rate to retrieve the nominal rate value from a Rate with Continuous compounding.
Examples
julia> Rate(0.01,Continuous())
Continuous(0.01)See also: Periodic
FinanceCore.Continuous — Method
Continuous(rate)A convenience constructor for Rate(rate, Continuous()). Use rate to retrieve the nominal rate value.
julia> Continuous(0.01)
Continuous(0.01)See also: Periodic
FinanceCore.Periodic — Type
Periodic(frequency)A type representing periodic interest compounding with the given frequency.
frequency will be converted to an Integer, and will round up to 8 decimal places (otherwise will throw an InexactError).
Use rate to retrieve the nominal rate value from a Rate with Periodic compounding.
Examples
Creating a semi-annual bond equivalent yield:
julia> Rate(0.01,Periodic(2))
Periodic(0.01, 2)See also: Continuous
FinanceCore.Periodic — Method
Periodic(rate, frequency)A convenience constructor for Rate(rate, Periodic(frequency)). Use rate to retrieve the nominal rate value.
Examples
Creating a semi-annual bond equivalent yield:
julia> Periodic(0.01,2)
Periodic(0.01, 2)See also: Continuous
FinanceCore.Quote — Type
Quote(price,instrument)The price(<:Real) is the observed value , and the instrument is the instrument/contract that the price is for.
This can be used, e.g., to calibrate a valuation model to prices for the given instruments - see FinanceModels.jl for more details.
FinanceCore.Rate — Method
Rate(rate::Real[, frequency = 1])
Rate(rate::Real, frequency::Frequency)
Rate(r::Rate[, frequency])Rate is a type that encapsulates an interest rate along with its compounding frequency.
Internally, all rates (including Periodic rates) are stored as their continuously compounded equivalent for performance. This means the internal field values will differ from the nominal rate. Use rate to retrieve the nominal rate value corresponding to the compounding frequency, and compounding to retrieve the compounding frequency.
Periodic rates can be constructed via Rate(rate,frequency) or Rate(rate,Periodic(frequency)). If not given a second argument, Rate(rate) is equivalent to Rate(rate,Periodic(1)).
Continuous rates can be constructed via Rate(rate, Inf) or Rate(rate,Continuous()).
Given a Rate, Rate(r) returns r, and Rate(r, frequency) converts r to frequency (a Frequency, or a number as above). The conversion keeps the force of interest and its numeric type exactly, and is the same as convert(frequency, r) and frequency(r).
Examples
julia> Rate(0.01,Continuous())
Continuous(0.01)
julia> Continuous(0.01)
Continuous(0.01)
julia> Continuous()(0.01)
Continuous(0.01)
julia> Rate(0.01,Periodic(2))
Periodic(0.01, 2)
julia> Periodic(0.01,2)
Periodic(0.01, 2)
julia> Periodic(2)(0.01)
Periodic(0.01, 2)
julia> Rate(0.01)
Periodic(0.01, 1)
julia> Rate(0.01,2)
Periodic(0.01, 2)
julia> Rate(0.01,Periodic(4))
Periodic(0.01, 4)
julia> Rate(0.01,Inf)
Continuous(0.01)
julia> rate(Periodic(0.01,2))
0.01
julia> Rate(Continuous(0.05), Periodic(2))
Periodic(0.05063024104885768, 2)
julia> Rate(Periodic(0.05, 2), Inf)
Continuous(0.049385225180743)FinanceCore.accumulation — Method
accumulation(rate, t)
accumulation(rate, from, to)Accumulate rate for a time t or for an interval (from, to). A number rate is taken as a rate compounded once per period, Periodic(rate, 1).
FinanceCore defines the interval form only for a constant rate (a Rate or a number); it accumulates over to - from. Other models, such as FinanceModels' yield curves, define their own interval method.
Examples
julia> accumulation(0.03, 10)
1.343916379344122
julia> accumulation(Periodic(0.03, 2), 10)
1.346855006550056
julia> accumulation(Continuous(0.03), 10)
1.3498588075760032
julia> accumulation(0.03, 5, 10)
1.1592740743FinanceCore.amount — Method
amount(x)If x is an object with an amount component (e.g. a Cashflow), will return that amount component, otherwise just x.
Examples
julia> FinanceCore.amount(Cashflow(1.,3.))
1.0
julia> FinanceCore.amount(1.)
1.0FinanceCore.compounding — Method
compounding(r::Rate)Returns the compounding frequency of the Rate.
Examples
julia> r = Continuous(0.03)
Continuous(0.03)
julia> compounding(r)
Continuous()
julia> r = Periodic(0.05, 2)
Periodic(0.05, 2)
julia> compounding(r)
Periodic(2)FinanceCore.discount — Method
discount(rate, t)
discount(rate, from, to)Discount rate for a time t or for an interval (from, to). A number rate is taken as a rate compounded once per period, Periodic(rate, 1).
FinanceCore defines the interval form only for a constant rate (a Rate or a number); it discounts over to - from. Other models, such as FinanceModels' yield curves, define their own interval method.
Examples
julia> discount(0.03, 10)
0.7440939148967252
julia> discount(Periodic(0.03, 2), 10)
0.7424704182237711
julia> discount(Continuous(0.03), 10)
0.7408182206817179
julia> discount(0.03, 5, 10)
0.862608784384164FinanceCore.forward — Method
forward(rate::Rate, from, to)
forward(rate::Rate, t)The forward rate over a period. A constant Rate is its own forward rate over every period, so both return rate. Other packages add methods for their models, such as FinanceModels' yield curves.
FinanceCore.internal_rate_of_return — Method
internal_rate_of_return(cashflows::AbstractVector)::Rate
internal_rate_of_return(cashflows::AbstractVector, timepoints)::Rate
internal_rate_of_return(cashflows::AbstractVector{<:Cashflow})::RateCalculate the internal rate of return with given timepoints. If no timepoints given, assumes equally spaced cashflows starting at time zero (0, 1, ..., n - 1 for n cashflows). cashflows and timepoints must have the same length, or a DimensionMismatch is thrown.
Returns a Periodic(rate, 1)Rate, or nothing if no root is found. Get the scalar rate by calling rate() on the result.
An empty collection of cashflows, like an all-zero one, returns nothing: there is no identifiable IRR, since every rate solves an identically zero pricing equation.
Example
julia> internal_rate_of_return([-100,110],[0,1]) # e.g. cashflows at time 0 and 1
Periodic(0.1, 1)
julia> internal_rate_of_return([-100,110]) # implied the same as above
Periodic(0.1, 1)Solver notes
First tries Newton's method (fast). If Newton does not converge, falls back to a robust root-finding search in continuous rate space over [-5, 3] (approximately [-0.993, 19.1] in periodic rate). Fallback roots are residual-validated; when multiple roots remain, returns the one nearest zero.
Derivatives
ForwardDiff derivatives of any order with respect to the cashflows or timepoints are supported, including nested dual numbers (for example ForwardDiff.hessian). Both stages solve on primal (non-dual) values. Implicit-function steps r ← r - (g(r) - g₀) / g′ for the pricing residual g, where g₀ is its primal value and g′ its primal slope at the root, then give the root its partials: the first gives dr = -(∂g/∂θ) / (∂g/∂r), and each step adds one order, so one step per dual layer suffices. The value is the primal IRR exactly. A root whose derivative vanishes (a repeated root) throws an ArgumentError, since its sensitivity is undefined.
FinanceCore.irr — Function
irr(cashflows::AbstractVector)
irr(cashflows::AbstractVector, timepoints)
irr(cashflows::AbstractVector{<:Cashflow})An alias for internal_rate_of_return.
FinanceCore.maturity — Function
maturity(contract)The time of the last payment of contract: a Cashflow's time, the later of a Composite's two maturities, or the maturity of a Quote's instrument.
FinanceCore.present_value — Method
present_value(yield_model, amounts, timepoints)
present_value(yield_model, cashflows)
present_value(yield_model, contract)Discount cashflows at yield_model: a Rate, a number (taken as Periodic(rate, 1)), or any model that defines discount. The valuation is as of time zero.
- With
timepoints, each amount is paid at the paired timepoint. ACashflowis paid at its own time, not the paired one. Amounts and timepoints pair by position (vectors from each one's first index) and must have the same length, whatever the collection: vectors, tuples, generators, or a single timepoint with a collection of one amount. Different lengths throw aDimensionMismatch, except that no amounts are worth zero whatever the times. Each collection is iterated once, so single-pass iterators work. - Without
timepoints, the collection is valued over itspairs: a number is paid at its key (the index of a vector, the key of aDict), and any other element, such as aCashflow, a contract or a nested collection, is valued on its own timing,present_value(yield_model, element). - A
Cashflowis its amount discounted from its time, and aCompositeis the sum of its two components' present values.
So present value is linear over self-timed contracts whose values share a reporting currency: pv(r, [a, b]) ≈ pv(r, a) + pv(r, b) ≈ pv(r, [b, a]), and pv(r, Composite(a, b)) == pv(r, a) + pv(r, b). A numeric vector is an indexed schedule: reordering it moves amounts to other times.
If your timepoints are dates, you can convert them into a floating point representation of the time interval using DayCounts.jl.
An empty collection of cashflows has a present value of exactly zero (positive zero): the value is fixed by linearity, and its numeric type follows a convention. For concrete amount, time and rate types it is the type a present value of such cashflows would have (a dual number with zero partials under ForwardDiff, a BigFloat for a BigFloat rate). When the element type says nothing about the amounts (Any[], Cashflow[], (), an empty generator), the rate or curve decides it. The zero is zero of the present value of a zero amount at time zero, so it has the valuation's type but does not depend on the rate's value (present_value(Continuous(Inf), Float64[]) is 0.0); the rate or curve is still evaluated at time zero to find that type, and can throw where that evaluation throws.
With no timepoints argument, present_value assumes amounts occur at the vector's indices (1, 2, ..., n), while internal_rate_of_return assumes they start at time zero (0, 1, ..., n-1). Pass explicit timepoints to avoid ambiguity.
Examples
julia> present_value(0.1, [10,20],[0,1])
28.18181818181818
julia> present_value(Continuous(0.1), [10,20],[0,1])
28.096748360719193
julia> present_value(Continuous(0.1), [10,20],[1,2])
25.422989241919232
julia> present_value(Continuous(0.1), [10,20])
25.422989241919232
julia> present_value(Continuous(0.1), [Cashflow(10, 1), Cashflow(20, 2)])
25.422989241919232
julia> present_value(Continuous(0.1), Any[10, Cashflow(20, 2)])
25.422989241919232FinanceCore.rate — Method
rate(r::Rate)Returns the nominal (untyped scalar) interest rate represented by the Rate, corresponding to its compounding frequency.
Since Rate internally stores all rates (including Periodic) as their continuously compounded equivalent for performance, rate recovers the nominal rate for the given compounding convention.
Examples
julia> r = Continuous(0.03)
Continuous(0.03)
julia> rate(r)
0.03
julia> r = Periodic(0.06, 2)
Periodic(0.06, 2)
julia> rate(r)
0.06FinanceCore.timepoint — Method
timepoint(x,t)If x is an object with a defined time component (e.g. a Cashflow), will return that time component, otherwise will return t. This is useful in handling situations where you want to handle either Cashflows or separate amount and time vectors.
Example
julia> FinanceCore.timepoint(Cashflow(1.,3.),"ignored")
3.0
julia> FinanceCore.timepoint(1.,4.)
4.0Unexported API
FinanceCore.Timepoint — Type
Timepoint(a)Summary ≡≡≡≡≡≡≡≡≡
Timepoint is a type alias for Union{T,Dates.Date} that can be used to represent a point in time. It can be either a Dates.Date or a Real number. If defined as a real number, the interpretation is the number of (fractional) periods since time zero.
Currently, the usage of Dates.Date is not well supported across the JuliaActuary ecosystem but this type is in place such that it can be built upon further.
Supertype Hierarchy ≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
Timepoint{T} = Union{T,Dates.Date} <: AnyFinanceCore.AbstractContract — Type
FinanceCore.AbstractContractThe supertype of contracts, such as Cashflow and Composite. FinanceModels adds bonds, swaps and options. A contract has a maturity, and present_value values it.
FinanceCore.Frequency — Type
FinanceCore.FrequencyThe compounding convention of a Rate: Periodic(n), compounded n times per period, or Continuous(). Calling a frequency on a number or a Rate gives a Rate in that convention: Periodic(2)(0.05) is Periodic(0.05, 2), and Continuous()(r) converts r.
Base.:+ — Method
+(Rate, T<:Real)
+(T<:Real, Rate)
+(Rate, Rate)Add in the nominal space of a rate's compounding convention, the way a spread is quoted over a base rate: Periodic(0.04, 2) + 0.01 is Periodic(0.05, 2).
With two Rates, the right operand is first converted to the left operand's convention, and the result has the left operand's compounding. Rates of the same convention therefore add nominally, while for different conventions the sum depends on the order.
To combine two rates independently of their conventions, add their continuously compounded forces with Continuous(a) + b. That is the rate whose discount factor is the product of theirs: discount(Continuous(a) + b, t) ≈ discount(a, t) * discount(b, t). For two annual rates it is (1 + a)(1 + b) - 1.
Examples
julia> Periodic(0.01, 2) + Periodic(0.04, 2)
Periodic(0.05, 2)
julia> Periodic(0.04, 2) + 0.01
Periodic(0.05, 2)
julia> Periodic(0.04, 1) + Continuous(0.01) # 1% converted to annual, then added
Periodic(0.05005016708416806, 1)
julia> Continuous(0.01) + Periodic(0.04, 1) # 4% annual converted to a force, then added
Continuous(0.0492207131532813)
julia> Continuous(Periodic(0.04, 1)) + Continuous(0.01) # the same sum in either order
Continuous(0.0492207131532813)Base.:- — Method
-(Rate, T<:Real)
-(T<:Real, Rate)
-(Rate, Rate)Subtract in the nominal space of a rate's compounding convention. As with +, the right operand of Rate - Rate is first converted to the left operand's convention, so (a - b) + b recovers a.
Examples
julia> Periodic(0.04, 2) - Periodic(0.01, 2)
Periodic(0.03, 2)
julia> Periodic(0.04, 2) - 0.01
Periodic(0.03, 2)Base.convert — Method
convert(cf::Frequency,r::Rate)Returns a Rate with an equivalent discount but represented with a different compounding frequency. The stored continuous rate and its numeric type are preserved exactly. The nominal rate returned by rate can still round or overflow in the requested convention; discounting and accumulation use the preserved continuous rate. Rate(r, cf) and cf(r) are the same conversion.
Examples
julia> r = Rate(0.01, Periodic(12))
Periodic(0.009999999999999998, 12)
julia> convert(Periodic(1), r)
Periodic(0.010045960887182024, 1)
julia> convert(Continuous(), r)
Continuous(0.009995835646702353)Base.isless — Method
isless(a::Rate, b::Rate)Total ordering of Rates by force of interest (the continuously compounded equivalent rate). Unlike numeric < and >, this orders negative zero before positive zero and NaN after all other values.
Defining isless enables sorting and order-based functions in Base, such as sort, minimum/maximum, and extrema, to work on Rates.
Examples
julia> sort([Continuous(0.03), Periodic(0.02, 2)])
2-element Vector{Rate{Float64}}:
Periodic(0.02, 2)
Continuous(0.03)
julia> minimum([Periodic(0.05, 2), Continuous(0.03)])
Continuous(0.03)FinanceCore.aggregate — Method
FinanceCore.aggregate(cashflows; key = identity)Group cashflows by key(time), comparing keys with ==. Return one Cashflow per key, in ascending key order. Its amount is the group's total and its time is the key.
For any key, the total amount is preserved (≈, as the sum is reordered). Present value is preserved (≈) when key leaves times unchanged, as the default identity does. A key that moves times, such as round, generally changes present value.
Examples
julia> FinanceCore.aggregate([Cashflow(1.0, 2.0), Cashflow(2.0, 1.0), Cashflow(3.0, 2.0)])
2-element Vector{Cashflow{Float64, Float64}}:
Cashflow{Float64, Float64}(2.0, 1.0)
Cashflow{Float64, Float64}(4.0, 2.0)
julia> FinanceCore.aggregate([Cashflow(1.0, 0.9), Cashflow(2.0, 1.2)]; key = round)
1-element Vector{Cashflow{Float64, Float64}}:
Cashflow{Float64, Float64}(3.0, 1.0)Please open an issue if you encounter any issues or confusion with the package.