# ActuaryUtilities.jl

`ActuaryUtilities.KeyRate`

`ActuaryUtilities.KeyRatePar`

`ActuaryUtilities.KeyRateZero`

`ActuaryUtilities.CTE`

`ActuaryUtilities.ConditionalTailExpectation`

`ActuaryUtilities.VaR`

`ActuaryUtilities.ValueAtRisk`

`ActuaryUtilities.accum_offset`

`ActuaryUtilities.breakeven`

`ActuaryUtilities.convexity`

`ActuaryUtilities.duration`

`ActuaryUtilities.duration`

`ActuaryUtilities.duration`

`ActuaryUtilities.eurocall`

`ActuaryUtilities.europut`

`ActuaryUtilities.internal_rate_of_return`

`ActuaryUtilities.irr`

`ActuaryUtilities.moic`

`ActuaryUtilities.present_value`

`ActuaryUtilities.present_values`

`ActuaryUtilities.price`

`ActuaryUtilities.pv`

`ActuaryUtilities.years_between`

`ActuaryUtilities.KeyRate`

— Type`KeyRate(timepoints,shift=0.001)`

A convenience constructor for `KeyRateZero`

.

**Extended Help**

`KeyRateZero`

is chosen as the default constructor because it has more attractive properties than `KeyRatePar`

:

- rates after the key
`timepoint`

remain unaffected by the`shift`

- e.g. this causes a 6-year zero coupon bond would have a negative duration if the 5-year par rate was used

`ActuaryUtilities.KeyRatePar`

— Type`KeyRatePar(timepoint,shift=0.001) <: KeyRateDuration`

Shift the par curve by the given amount at the given timepoint. Use in conjunction with `duration`

to calculate the key rate duration.

Unlike other duration statistics which are computed using analytic derivatives, `KeyRateDuration`

s are computed via a shift-and-compute the yield curve approach.

`KeyRatePar`

is more commonly reported (than `KayRateZero`

) in the fixed income markets, even though the latter has more analytically attractive properties. See the discussion of KeyRateDuration in the Yields.jl docs.

`ActuaryUtilities.KeyRateZero`

— Type`KeyRateZero(timepoint,shift=0.001) <: KeyRateDuration`

Shift the par curve by the given amount at the given timepoint. Use in conjunction with `duration`

to calculate the key rate duration.

Unlike other duration statistics which are computed using analytic derivatives, `KeyRateDuration`

is computed via a shift-and-compute the yield curve approach.

`KeyRateZero`

is less commonly reported (than `KayRatePar`

) in the fixed income markets, even though the latter has more analytically attractive properties. See the discussion of KeyRateDuration in the Yields.jl docs.

`ActuaryUtilities.CTE`

— Method`CTE(v::AbstractArray,p::Real;rev::Bool=false)`

The average of the values ≥ the `p`

th percentile of the vector `v`

is the Conditiona Tail Expectation. Assumes more positive values are higher risk measures, so a higher p will return a more positive number, but this can be reversed if `rev`

is `true`

.

May also be called with `ConditionalTailExpectation(...)`

.

Also known as Tail Value at Risk (TVaR), or Tail Conditional Expectation (TCE)

`ActuaryUtilities.ConditionalTailExpectation`

— Function`ActuaryUtilities.VaR`

— Method`VaR(v::AbstractArray,p::Real;rev::Bool=false)`

The `p`

th quantile of the vector `v`

is the Value at Risk. Assumes more positive values are higher risk measures, so a higher p will return a more positive number, but this can be reversed if `rev`

is `true`

.

Also can be called with `ValueAtRisk(...)`

.

`ActuaryUtilities.ValueAtRisk`

— Function`ActuaryUtilities.accum_offset`

— Method`accum_offset(x; op=*, init=1.0)`

A shortcut for the common operation wherein a vector is scanned with an operation, but has an initial value and the resulting array is offset from the traditional accumulate.

This is a common pattern when calculating things like survivorship given a mortality vector and you want the first value of the resulting vector to be `1.0`

, and the second value to be `1.0 * x[1]`

, etc.

Two keyword arguments:

`op`

is the binary (two argument) operator you want to use, such as`*`

or`+`

`init`

is the initial value in the returned array

**Examples**

```
julia> accum_offset([0.9, 0.8, 0.7])
3-element Array{Float64,1}:
1.0
0.9
0.7200000000000001
julia> accum_offset(1:5) # the product of elements 1:n, with the default `1` as the first value
5-element Array{Int64,1}:
1
1
2
6
24
julia> accum_offset(1:5,op=+)
5-element Array{Int64,1}:
1
2
4
7
11
```

`ActuaryUtilities.breakeven`

— Method```
breakeven(yield, cashflows::Vector)
breakeven(yield, cashflows::Vector,times::Vector)
```

Calculate the time when the accumulated cashflows breakeven given the yield.

Assumptions:

- cashflows occur at the end of the period
- cashflows evenly spaced with the first one occuring at time zero if
`times`

not given

Returns `nothing`

if cashflow stream never breaks even.

```
julia> breakeven(0.10, [-10,1,2,3,4,8])
5
julia> breakeven(0.10, [-10,15,2,3,4,8])
1
julia> breakeven(0.10, [-10,-15,2,3,4,8]) # returns the `nothing` value
```

`ActuaryUtilities.convexity`

— Method```
convexity(yield,cfs,times)
convexity(yield,valuation_function)
```

Calculates the convexity. - `yield`

should be a fixed effective yield (e.g. `0.05`

). - `times`

may be omitted and it will assume `cfs`

are evenly spaced beginning at the end of the first period.

**Examples**

Using vectors of cashflows and times

```
julia> times = 1:5
julia> cfs = [0,0,0,0,100]
julia> duration(0.03,cfs,times)
4.854368932038834
julia> duration(Macaulay(),0.03,cfs,times)
5.0
julia> duration(Modified(),0.03,cfs,times)
4.854368932038835
julia> convexity(0.03,cfs,times)
28.277877274012614
```

Using any given value function:

```
julia> lump_sum_value(amount,years,i) = amount / (1 + i ) ^ years
julia> my_lump_sum_value(i) = lump_sum_value(100,5,i)
julia> duration(0.03,my_lump_sum_value)
4.854368932038835
julia> convexity(0.03,my_lump_sum_value)
28.277877274012617
```

`ActuaryUtilities.duration`

— Method```
duration(keyrate::KeyRateDuration,curve,cashflows)
duration(keyrate::KeyRateDuration,curve,cashflows,timepoints)
duration(keyrate::KeyRateDuration,curve,cashflows,timepoints,krd_points)
```

Calculate the key rate duration by shifting the **zero** (not par) curve by the kwarg `shift`

at the timepoint specified by a KeyRateDuration(time).

The approach is to carve up the curve into `krd_points`

(default is the unit steps between `1`

and the last timepoint of the casfhlows). The zero rate corresponding to the timepoint within the `KeyRateDuration`

is shifted by `shift`

(specified by the `KeyRateZero`

or `KeyRatePar`

constructors. A new curve is created from the shifted rates. This means that the "width" of the shifted section is ± 1 time period, unless specific points are specified via `krd_points`

.

The `curve`

may be any Yields.jl curve (e.g. does not have to be a curve constructed via `Yields.Zero(...)`

).

!!! Experimental: Due to the paucity of examples in the literature, this feature does not have unit tests like the rest of JuliaActuary functionality. Additionally, the API may change in a future major/minor version update.

**Examples**

```
julia> riskfree_maturities = [0.5, 1.0, 1.5, 2.0];
julia> riskfree = [0.05, 0.058, 0.064,0.068];
julia> rf_curve = Yields.Zero(riskfree,riskfree_maturities);
julia> cfs = [10,10,10,10,10];
julia> duration(KeyRate(1),rf_curve,cfs)
8.932800152336995
```

**Extended Help**

Key Rate Duration is not a well specified topic in the literature and in practice. The reference below suggest that shocking the par curve is more common in practice, but that the zero curve produces more consistent results. Future versions may support shifting the par curve.

References:

- Quant Finance Stack Exchange: To compute key rate duration, shall I use par curve or zero curve?
- (Financial Exam Help 123](http://www.financialexamhelp123.com/key-rate-duration/)

`ActuaryUtilities.duration`

— Method`duration(d1::Date, d2::Date)`

Compute the duration given two dates, which is the number of years since the first date. The interval `[0,1)`

is defined as having duration `1`

. Can return negative durations if second argument is before the first.

```
julia> issue_date = Date(2018,9,30);
julia> duration(issue_date , Date(2019,9,30) )
2
julia> duration(issue_date , issue_date)
1
julia> duration(issue_date , Date(2018,10,1) )
1
julia> duration(issue_date , Date(2019,10,1) )
2
julia> duration(issue_date , Date(2018,6,30) )
0
julia> duration(Date(2018,9,30),Date(2017,6,30))
-1
```

`ActuaryUtilities.duration`

— Method```
duration(Macaulay(),interest_rate,cfs,times)
duration(Modified(),interest_rate,cfs,times)
duration(DV01(),interest_rate,cfs,times)
duration(interest_rate,cfs,times) # Modified Duration
duration(interest_rate,valuation_function) # Modified Duration
```

Calculates the Macaulay, Modified, or DV01 duration. `times`

may be ommitted and the valuation will assume evenly spaced cashflows starting at the end of the first period.

`interest_rate`

should be a fixed effective yield (e.g.`0.05`

).

When not given `Modified()`

or `Macaulay()`

as an argument, will default to `Modified()`

.

**Examples**

Using vectors of cashflows and times

```
julia> times = 1:5
julia> cfs = [0,0,0,0,100]
julia> duration(0.03,cfs,times)
4.854368932038834
julia> duration(Macaulay(),0.03,cfs,times)
5.0
julia> duration(Modified(),0.03,cfs,times)
4.854368932038835
julia> convexity(0.03,cfs,times)
28.277877274012614
```

Using any given value function:

```
julia> lump_sum_value(amount,years,i) = amount / (1 + i ) ^ years
julia> my_lump_sum_value(i) = lump_sum_value(100,5,i)
julia> duration(0.03,my_lump_sum_value)
4.854368932038835
julia> convexity(0.03,my_lump_sum_value)
28.277877274012617
```

`ActuaryUtilities.eurocall`

— Method`eurocall(;S=1.,K=1.,τ=1,r,σ,q=0.)`

Calculate the Black-Scholes implied option price for a european call, where:

`S`

is the current asset price`K`

is the strike or exercise price`τ`

is the time remaining to maturity (can be typed with \tau[tab])`r`

is the continuously compounded risk free rate`σ`

is the (implied) volatility (can be typed with \sigma[tab])`q`

is the continuously paid dividend rate

Rates should be input as rates (not percentages), e.g.: `0.05`

instead of `5`

for a rate of five percent.

!!! Experimental: this function is well-tested, but the derivatives functionality (API) may change in a future version of ActuaryUtilities.

**Extended Help**

This is the same as the formulation presented in the dividend extension of the BS model in Wikipedia.

**Other general comments:**

- Swap/OIS curves are generally better sources for
`r`

than government debt (e.g. US Treasury) due to the collateralized nature of swap instruments. - (Implied) volatility is characterized by a curve that is a function of the strike price (among other things), so take care when using
- Yields.jl can assist with converting rates to continuously compounded if you need to perform conversions.

`ActuaryUtilities.europut`

— Method`europut(;S=1.,K=1.,τ=1,r,σ,q=0.)`

Calculate the Black-Scholes implied option price for a european call, where:

`S`

is the current asset price`K`

is the strike or exercise price`τ`

is the time remaining to maturity (can be typed with \tau[tab])`r`

is the continuously compounded risk free rate`σ`

is the (implied) volatility (can be typed with \sigma[tab])`q`

is the continuously paid dividend rate

Rates should be input as rates (not percentages), e.g.: `0.05`

instead of `5`

for a rate of five percent.

!!! Experimental: this function is well-tested, but the derivatives functionality (API) may change in a future version of ActuaryUtilities.

**Extended Help**

This is the same as the formulation presented in the dividend extension of the BS model in Wikipedia.

**Other general comments:**

- Swap/OIS curves are generally better sources for
`r`

than government debt (e.g. US Treasury) due to the collateralized nature of swap instruments. - (Implied) volatility is characterized by a curve that is a function of the strike price (among other things), so take care when using
- Yields.jl can assist with converting rates to continuously compounded if you need to perform conversions.

`ActuaryUtilities.internal_rate_of_return`

— Method```
internal_rate_of_return(cashflows::vector)::Yields.Rate
internal_rate_of_return(cashflows::Vector, timepoints::Vector)::Yields.Rate
```

Calculate the internal*rate*of_return with given timepoints. If no timepoints given, will assume that a series of equally spaced cashflows, assuming the first cashflow occurring at time zero and subsequent elements at time 1, 2, 3, ..., n.

Returns a Yields.Rate type with periodic compounding once per period (e.g. annual effective if the `timepoints`

given represent years). Get the scalar rate by calling `Yields.rate()`

on the result.

**Example**

```
julia> internal_rate_of_return([-100,110],[0,1]) # e.g. cashflows at time 0 and 1
0.10000000001652906
julia> internal_rate_of_return([-100,110]) # implied the same as above
0.10000000001652906
```

**Solver notes**

Will try to return a root within the range [-2,2]. If the fast solver does not find one matching this condition, then a more robust search will be performed over the [.99,2] range.

The solution returned will be in the range [-2,2], but may not be the one nearest zero. For a slightly slower, but more robust version, call `ActuaryUtilities.irr_robust(cashflows,timepoints)`

directly.

`ActuaryUtilities.irr`

— Function```
irr(cashflows::vector)
irr(cashflows::Vector, timepoints::Vector)
An alias for `internal_rate_of_return`.
```

`ActuaryUtilities.moic`

— Method`moic(cashflows<:AbstractArray)`

The multiple on invested capital ("moic") is the un-discounted sum of distributions divided by the sum of the contributions. The function assumes that negative numbers in the array represent contributions and positive numbers represent distributions.

**Examples**

```
julia> moic([-10,20,30])
5.0
```

`ActuaryUtilities.present_value`

— Method```
present_value(interest, cashflows::Vector, timepoints)
present_value(interest, cashflows::Vector)
```

Discount the `cashflows`

vector at the given `interest_interestrate`

, with the cashflows occurring at the times specified in `timepoints`

. If no `timepoints`

given, assumes that cashflows happen at times 1,2,...,n.

The `interest`

can be an `InterestCurve`

, a single scalar, or a vector wrapped in an `InterestCurve`

.

**Examples**

```
julia> present_value(0.1, [10,20],[0,1])
28.18181818181818
julia> present_value(Yields.Forward([0.1,0.2]), [10,20],[0,1])
28.18181818181818 # same as above, because first cashflow is at time zero
```

Example on how to use real dates using the DayCounts.jl package

```
using DayCounts
dates = Date(2012,12,31):Year(1):Date(2013,12,31)
times = map(d -> yearfrac(dates[1], d, DayCounts.Actual365Fixed()),dates) # [0.0,1.0]
present_value(0.1, [10,20],times)
# output
28.18181818181818
```

`ActuaryUtilities.present_values`

— Method```
present_value(interest, cashflows::Vector, timepoints)
present_value(interest, cashflows::Vector)
```

Efficiently calculate a vector representing the present value of the given cashflows at each period prior to the given timepoint.

**Examples**

```
julia> present_values(0.00, [1,1,1])
[3,2,1]
julia> present_values(Yields.Forward([0.1,0.2]), [10,20],[0,1])
2-element Vector{Float64}:
28.18181818181818
18.18181818181818
```

`ActuaryUtilities.price`

— Method`price(...)`

The absolute value of the `present_value(...)`

.

**Extended help**

Using `price`

can be helpful if the directionality of the value doesn't matter. For example, in the common usage, duration is more interested in the change in price than present value, so `price`

is used there.

`ActuaryUtilities.pv`

— Function```
pv()
An alias for `present_value`.
```

`ActuaryUtilities.years_between`

— Function`Years_Between(d1::Date, d2::Date)`

Compute the number of integer years between two dates, with the first date typically before the second. Will return negative number if first date is after the second. Use third argument to indicate if calendar anniversary should count as a full year.

**Examples**

```
julia> d1 = Date(2018,09,30);
julia> d2 = Date(2019,09,30);
julia> d3 = Date(2019,10,01);
julia> years_between(d1,d3)
1
julia> years_between(d1,d2,false) # same month/day but `false` overlap
0
julia> years_between(d1,d2) # same month/day but `true` overlap
1
julia> years_between(d1,d2) # using default `true` overlap
1
```