Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DateModel #152

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
88749be
rewrite first cut
alecloudenback May 27, 2023
545911d
use Transducers instead of iteration interface
alecloudenback Jun 10, 2023
4cd1cd2
simplify `Composite`
alecloudenback Jun 10, 2023
391a703
format
alecloudenback Jun 10, 2023
6fa78e4
more work in progress incl Forward and derivs
alecloudenback Jun 12, 2023
9939061
lots of progress
alecloudenback Jun 15, 2023
6621179
re-incorporate `RateCombination` (now called `CompositeYield`)
alecloudenback Jun 16, 2023
b624df5
more progress
alecloudenback Jun 16, 2023
c4ff533
bootstrap
alecloudenback Jun 17, 2023
0997390
progress
alecloudenback Jun 18, 2023
a496b22
more tests passing
alecloudenback Jun 18, 2023
4632ddc
progress
alecloudenback Jun 19, 2023
cd14f1e
fix `Floating`
alecloudenback Jun 19, 2023
766803f
fix floating test
alecloudenback Jun 19, 2023
ad56206
CompositeYield tests
alecloudenback Jun 19, 2023
6b13e83
progress
alecloudenback Jun 20, 2023
c4abc39
simplify SW cashflow matrix
alecloudenback Jun 20, 2023
94c6619
SW complete
alecloudenback Jun 21, 2023
8a040d1
NS progress
alecloudenback Jun 21, 2023
e2f8f9a
NSS tests passing (had to widen tolerance given different solve)
alecloudenback Jun 25, 2023
9375349
cleanup
alecloudenback Jun 25, 2023
d931c56
move things up to FinanceCore
alecloudenback Jun 26, 2023
4a44fe1
progress
alecloudenback Jul 3, 2023
ece96fb
faster coupons
alecloudenback Jul 4, 2023
8d1e753
tests pass locally, need dev'ed version of ActuaryUtilities and Finan…
alecloudenback Jul 5, 2023
ec7cc13
change `CompoundingFrequency` to `Frequency` since it's used in more …
alecloudenback Jul 5, 2023
8ca3b4f
add commentary
alecloudenback Jul 6, 2023
ec4b544
simplify code and comments for floating bond
alecloudenback Jul 7, 2023
f9d5b34
further simplify user code
alecloudenback Jul 7, 2023
3cb2806
DateModel
alecloudenback Jul 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 19 additions & 20 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
name = "Yields"
uuid = "d7e99b2f-e7f3-4d9e-9f01-2338fc023ad3"
name = "FinanceModels"
uuid = "77f2ae65-bdde-421f-ae9d-22f1af19dd76"
authors = ["Alec Loudenback <[email protected]> and contributors"]
version = "3.5.0"
version = "4.0.0"

[deps]
AccessibleOptimization = "d88a00a0-4a21-4fe4-a515-e2123c37b885"
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
BSplineKit = "093aae92-e908-43d7-9660-e50ee39d5a0a"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
FinanceCore = "b9b1ffdd-6612-4b69-8227-7663be06e089"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LsqFit = "2fda8390-95c7-5789-9bda-21331edee243"
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba"
OptimizationMetaheuristics = "3aafef2f-86ae-4776-b337-85a36adf0b55"
OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Transducers = "28d57a85-8fef-5791-bfe6-a80928e7c999"
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"

[compat]
BSplineKit = "^0.8"
FinanceCore = "^1"
ForwardDiff = "^0.10"
LsqFit = "^0.12"
Optim = "^1"
Reexport = "^1.2"
Roots = "^1"
PrecompileTools = "^1"
UnicodePlots = "^2"
julia = "^1.6"
julia = "1.6"

[extras]
ActuaryUtilities = "bdd23359-8b1c-4f88-b89b-d11982a786f4"
DecFP = "55939f99-70c6-5e9b-8bb0-5071ed7d61fd"
FinanceCore = "b9b1ffdd-6612-4b69-8227-7663be06e089"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"

[targets]
test = ["Test"]
test = ["Test", "FinanceCore", "ActuaryUtilities", "DecFP", "TestItemRunner"]
76 changes: 38 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
# Yields.jl
# FinanceModels.jl

[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaActuary.github.io/Yields.jl/stable)
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaActuary.github.io/Yields.jl/dev)
[![Build Status](https://github.com/JuliaActuary/Yields.jl/workflows/CI/badge.svg)](https://github.com/JuliaActuary/Yields.jl/actions)
[![Coverage](https://codecov.io/gh/JuliaActuary/Yields.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaActuary/Yields.jl)
[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaActuary.github.io/FinanceModels.jl/stable)
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaActuary.github.io/FinanceModels.jl/dev)
[![Build Status](https://github.com/JuliaActuary/FinanceModels.jl/workflows/CI/badge.svg)](https://github.com/JuliaActuary/FinanceModels.jl/actions)
[![Coverage](https://codecov.io/gh/JuliaActuary/FinanceModels.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaActuary/FinanceModels.jl)

**Yields.jl** provides a simple interface for constructing, manipulating, and using yield curves for modeling purposes.
**FinanceModels.jl** provides a simple interface for constructing, manipulating, and using yield curves for modeling purposes.

It's intended to provide common functionality around modeling interest rates, spreads, and miscellaneous yields across the JuliaActuary ecosystem (though not limited to use in JuliaActuary packages).
It's intended to provide common functionality around modeling interest rates, spreads, and miscellaneous FinanceModels across the JuliaActuary ecosystem (though not limited to use in JuliaActuary packages).

![anim_fps2](https://user-images.githubusercontent.com/711879/174458687-860c5d7f-e125-46a9-a706-7d113f1e243b.gif)


## QuickStart

```julia
using Yields
using FinanceModels

riskfree_maturities = [0.5, 1.0, 1.5, 2.0]
riskfree = [5.0, 5.8, 6.4, 6.8] ./ 100 #spot rates, annual effective if unspecified

spread_maturities = [0.5, 1.0, 1.5, 3.0] # different maturities
spread = [1.0, 1.8, 1.4, 1.8] ./ 100 # spot spreads

rf_curve = Yields.Zero(riskfree,riskfree_maturities)
spread_curve = Yields.Zero(spread,spread_maturities)
rf_curve = FinanceModels.Zero(riskfree,riskfree_maturities)
spread_curve = FinanceModels.Zero(spread,spread_maturities)


yield = rf_curve + spread_curve # additive combination of the two curves
Expand All @@ -38,10 +38,10 @@ discount(yield,1.5) # 1 / (1 + 0.064 + 0.014) ^ 1.5

Rates are types that wrap scalar values to provide information about how to determine `discount` and `accumulation` factors.

There are two `CompoundingFrequency` types:
There are two `Frequency` types:

- `Yields.Periodic(m)` for rates that compound `m` times per period (e.g. `m` times per year if working with annual rates).
- `Yields.Continuous()` for continuously compounding rates.
- `FinanceModels.Periodic(m)` for rates that compound `m` times per period (e.g. `m` times per year if working with annual rates).
- `FinanceModels.Continuous()` for continuously compounding rates.

#### Examples

Expand All @@ -64,7 +64,7 @@ Periodic.([0.02,0.03,0.04],2)
Continuous.([0.02,0.03,0.04])
```

Rates can also be constructed by specifying the `CompoundingFrequency` and then passing a scalar rate:
Rates can also be constructed by specifying the `Frequency` and then passing a scalar rate:

```julia
Periodic(1)(0.05)
Expand All @@ -76,10 +76,10 @@ Continuous()(0.05)
Convert rates between different types with `convert`. E.g.:

```julia-repl
r = Rate(Yields.Periodic(12),0.01) # rate that compounds 12 times per rate period (ie monthly)
r = Rate(FinanceModels.Periodic(12),0.01) # rate that compounds 12 times per rate period (ie monthly)

convert(Yields.Periodic(1),r) # convert monthly rate to annual effective
convert(Yields.Continuous(),r) # convert monthly rate to continuous
convert(FinanceModels.Periodic(1),r) # convert monthly rate to annual effective
convert(FinanceModels.Continuous(),r) # convert monthly rate to continuous
```

#### Arithmetic
Expand All @@ -94,11 +94,11 @@ There are a several ways to construct a yield curve object. If `maturities` is o

There is a set of constructor methods which will return a yield curve calibrated to the given inputs.

- `Yields.Zero(rates,maturities)` using a vector of zero rates (sometimes referred to as "spot" rates)
- `Yields.Forward(rates,maturities)` using a vector of forward rates
- `Yields.Par(rates,maturities)` takes a series of yields for securities priced at par. Assumes that maturities <= 1 year do not pay coupons and that after one year, pays coupons with frequency equal to the CompoundingFrequency of the corresponding rate (2 by default).
- `Yields.CMT(rates,maturities)` takes the most commonly presented rate data (e.g. [Treasury.gov](https://www.treasury.gov/resource-center/data-chart-center/interest-rates/Pages/TextView.aspx?data=yield)) and bootstraps the curve given the combination of bills and bonds.
- `Yields.OIS(rates,maturities)` takes the most commonly presented rate data for overnight swaps and bootstraps the curve. Rates assume a single settlement for <1 year and quarterly settlements for 1 year and above.
- `FinanceModels.Zero(rates,maturities)` using a vector of zero rates (sometimes referred to as "spot" rates)
- `FinanceModels.Forward(rates,maturities)` using a vector of forward rates
- `FinanceModels.Par(rates,maturities)` takes a series of FinanceModels for securities priced at par. Assumes that maturities <= 1 year do not pay coupons and that after one year, pays coupons with frequency equal to the Frequency of the corresponding rate (2 by default).
- `FinanceModels.CMT(rates,maturities)` takes the most commonly presented rate data (e.g. [Treasury.gov](https://www.treasury.gov/resource-center/data-chart-center/interest-rates/Pages/TextView.aspx?data=yield)) and bootstraps the curve given the combination of bills and bonds.
- `FinanceModels.OIS(rates,maturities)` takes the most commonly presented rate data for overnight swaps and bootstraps the curve. Rates assume a single settlement for <1 year and quarterly settlements for 1 year and above.

##### Fitting techniques

Expand All @@ -110,36 +110,36 @@ There are multiple curve fitting methods available:
- `NelsonSiegel(τ_initial=1.0)`
- `NelsonSiegelSvensson(τ_initial=[1.0,1.0])`

To specify which fitting method to use, pass the object to as the first parameter to the above set of constructors, for example: `Yields.Par(NelsonSiegel(),rates,maturities)`.
To specify which fitting method to use, pass the object to as the first parameter to the above set of constructors, for example: `FinanceModels.Par(NelsonSiegel(),rates,maturities)`.

#### Kernel Methods

- `Yields.SmithWilson` curve (used for [discounting in the EU Solvency II framework](https://www.eiopa.europa.eu/sites/default/files/risk_free_interest_rate/12092019-technical_documentation.pdf)) can be constructed either directly by specifying its inner representation or by calibrating to a set of cashflows with known prices.
- These cashflows can conveniently be constructed with a Vector of `Yields.ZeroCouponQuote`s, `Yields.SwapQuote`s, or `Yields.BulletBondQuote`s.
- `FinanceModels.SmithWilson` curve (used for [discounting in the EU Solvency II framework](https://www.eiopa.europa.eu/sites/default/files/risk_free_interest_rate/12092019-technical_documentation.pdf)) can be constructed either directly by specifying its inner representation or by calibrating to a set of cashflows with known prices.
- These cashflows can conveniently be constructed with a Vector of `FinanceModels.ZeroCouponQuote`s, `FinanceModels.SwapQuote`s, or `FinanceModels.BulletBondQuote`s.

#### Other Curves

- `Yields.Constant(rate)` takes a single constant rate for all times
- `Yields.Step(rates,maturities)` doesn't interpolate - the rate is flat up to the corresponding time in `times`
- `FinanceModels.Constant(rate)` takes a single constant rate for all times
- `FinanceModels.Step(rates,maturities)` doesn't interpolate - the rate is flat up to the corresponding time in `times`

### Functions

Most of the above yields have the following defined (goal is to have them all):
Most of the above FinanceModels have the following defined (goal is to have them all):

- `discount(curve,from,to)` or `discount(curve,to)` gives the discount factor
- `accumulation(curve,from,to)` or `accumulation(curve,to)` gives the accumulation factor
- `zero(curve,time)` or `zero(curve,time,CompoundingFrequency)` gives the zero-coupon spot rate for the given time.
- `zero(curve,time)` or `zero(curve,time,Frequency)` gives the zero-coupon spot rate for the given time.
- `forward(curve,from,to)` gives the zero rate between the two given times
- `par(curve,time)` gives the coupon-paying par equivalent rate for the given time.

### Combinations

Different yield objects can be combined with addition or subtraction. See the [Quickstart](#quickstart) for an example.

When adding a `Yields.AbstractYield` with a scalar or vector, that scalar or vector will be promoted to a yield type via [`Yield()`](#yield). For example:
When adding a `FinanceModels.AbstractYield` with a scalar or vector, that scalar or vector will be promoted to a yield type via [`Yield()`](#yield). For example:

```julia
y1 = Yields.Constant(0.05)
y1 = FinanceModels.Constant(0.05)
y2 = y1 + 0.01 # y2 is a yield of 0.06
```

Expand All @@ -150,8 +150,8 @@ Constructed curves can be shifted so that a future timepoint becomes the effecti
```julia-repl
julia> zero = [5.0, 5.8, 6.4, 6.8] ./ 100
julia> maturity = [0.5, 1.0, 1.5, 2.0]
julia> curve = Yields.Zero(zero, maturity)
julia> fwd = Yields.ForwardStarting(curve, 1.0)
julia> curve = FinanceModels.Zero(zero, maturity)
julia> fwd = FinanceModels.ForwardStarting(curve, 1.0)

julia> discount(curve,1,2)
0.9275624570410582
Expand All @@ -162,19 +162,19 @@ julia> discount(fwd,1) # `curve` has effectively been reindexed to `1.0`

## Exported vs Un-exported Functions

Generally, CamelCase methods which construct a datatype are exported as they are unlikely to conflict with other parts of code that may be written. For example, `rate` is un-exported (it must be called with `Yields.rate(...)`) because `rate` is likely a very commonly defined variable within actuarial and financial contexts and there is a high risk of conflicting with defined variables.
Generally, CamelCase methods which construct a datatype are exported as they are unlikely to conflict with other parts of code that may be written. For example, `rate` is un-exported (it must be called with `FinanceModels.rate(...)`) because `rate` is likely a very commonly defined variable within actuarial and financial contexts and there is a high risk of conflicting with defined variables.

Consider using `import Yields` which would require qualifying all methods, but alleviates any namespace conflicts and has the benefit of being explicit about the calls (internally we prefer this in the package design to keep dependencies and their usage clear).
Consider using `import FinanceModels` which would require qualifying all methods, but alleviates any namespace conflicts and has the benefit of being explicit about the calls (internally we prefer this in the package design to keep dependencies and their usage clear).

## Internals

For time-variant yields (ie yield *curves*), the inputs are converted to spot rates and interpolated using quadratic B-splines by default (see documentation for alternatives, such as linear interpolations).
For time-variant FinanceModels (ie yield *curves*), the inputs are converted to spot rates and interpolated using quadratic B-splines by default (see documentation for alternatives, such as linear interpolations).

### Combination Implementation

[Combinations](#combinations) track two different curve objects and are not combined into a single underlying data structure. This means that you may achieve better performance if you combine the rates before constructing a `Yields` representation. The exception to this is `Constant` curves, which *do* get combined into a single structure that is as performant as pre-combined rate structure.
[Combinations](#combinations) track two different curve objects and are not combined into a single underlying data structure. This means that you may achieve better performance if you combine the rates before constructing a `FinanceModels` representation. The exception to this is `Constant` curves, which *do* get combined into a single structure that is as performant as pre-combined rate structure.

## Related Packages

- [**`InterestRates.jl`**](https://github.com/felipenoris/InterestRates.jl) specializes in fast rate calculations aimed at valuing fixed income contracts, with business-day-level accuracy.
- Comparative comments: **`Yields.jl`** does not try to provide as precise controls over the timing, structure, and interpolation of the curve. Instead, **`Yields.jl`** provides a minimal, but flexible and intuitive interface for common modeling needs.
- Comparative comments: **`FinanceModels.jl`** does not try to provide as precise controls over the timing, structure, and interpolation of the curve. Instead, **`FinanceModels.jl`** provides a minimal, but flexible and intuitive interface for common modeling needs.
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Yields = "d7e99b2f-e7f3-4d9e-9f01-2338fc023ad3"
FinanceModels = "77f2ae65-bdde-421f-ae9d-22f1af19dd76"
12 changes: 6 additions & 6 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using Yields
using FinanceModels
using Documenter

makedocs(;
modules=[Yields],
modules=[FinanceModels],
authors="Alec Loudenback <[email protected]> and contributors",
repo="https://github.com/JuliaActuary/Yields.jl/blob/{commit}{path}#L{line}",
sitename="Yields.jl",
repo="https://github.com/JuliaActuary/FinanceModels.jl/blob/{commit}{path}#L{line}",
sitename="FinanceModels.jl",
format=Documenter.HTML(;
prettyurls=get(ENV, "CI", "false") == "true",
canonical="https://JuliaActuary.github.io/Yields.jl",
canonical="https://JuliaActuary.github.io/FinanceModels.jl",
assets=String[],
),
pages=[
Expand All @@ -19,5 +19,5 @@ makedocs(;
)

deploydocs(;
repo="github.com/JuliaActuary/Yields.jl",
repo="github.com/JuliaActuary/FinanceModels.jl",
)
33 changes: 33 additions & 0 deletions docs/src/Updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# FinanceModels.jl

## Design

- **Contracts** represent insturments that ultimately obligate a payment of cashflows, which may or may not be scenario dependant.
- **Quotes** are observed or reference prices that may be used to `fit` models.
- **Models** are the combination of **assumptions** and **logic** that can then be used to realize the assumed cashflows that arise from a contract.

## Motivation

FinanceModels.jl is the evolution of Yields.jl. Yields.jl was originally designed for very nice usage of term structures of yield curves, but three aspects held it back:

1. The design was very oriented towards interest rates, and it was awkward to stick, e.g. volatility models into a package called Yields.jl
2. The API for contructing curves was inconsistent because there are different ways to construct a given curve and the inputs to constructing a simple bootstrapped curve with a spline through given yields vs a best-fit of a variety of instrumnets was simply a different paradigm.
3. There was a lack of ability to even express some types of contracts that are useful for model-fitting or modeling in general.

## TODOs
- `bond.frequency.frequency` is awkward
- Core contracts:
- Composite contact (e.g. Fixed + Float -> Swap)
- Forward contact
- Derivatives?
- distinguish between clean and dirty prices
- Projections
- Everythign is currently coerced to a F64/F64 Cashflow, but would like to be flexible with amount and timepoints
- How to integrate Dates?
- Core methods:
- port Yields.jl methods
- Ergonomics:
-
- Package design:
- promote `pv` to FinanceCore given it's utility here
- promote `Cashflow` up to FC
12 changes: 6 additions & 6 deletions docs/src/api.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Yields API Reference
# FinanceModels API Reference

Please [open an issue](https://github.com/JuliaActuary/Yields.jl/issues) if you encounter any issues or confusion with the package.
Please [open an issue](https://github.com/JuliaActuary/FinanceModels.jl/issues) if you encounter any issues or confusion with the package.

## Rate Types

Expand All @@ -13,7 +13,7 @@ For example, if we construct a curve like this:
rates =[0.01, 0.01, 0.03, 0.05, 0.07, 0.16, 0.35, 0.92, 1.40, 1.74, 2.31, 2.41] ./ 100
mats = [1/12, 2/12, 3/12, 6/12, 1, 2, 3, 5, 7, 10, 20, 30]

curve = Yields.CMT(rates,mats)
curve = FinanceModels.CMT(rates,mats)
```

Then rates from this curve will be typed. For example:
Expand All @@ -22,7 +22,7 @@ Then rates from this curve will be typed. For example:
z = zero(c,10)
```

Now, `z` will be: `Yields.Rate{Float64, Continuous}(0.01779624378877313, Continuous())`
Now, `z` will be: `FinanceModels.Rate{Float64, Continuous}(0.01779624378877313, Continuous())`

This `Rate` has both the rate an the compounding convention embedded in the datatype.

Expand All @@ -33,11 +33,11 @@ using ActuaryUtilities
present_values(z,cashflows)
```

If you need to extract the rate for some reason, you can get the rate by calling `Yields.rate(...)`. Using the above example, `Yields.rate(z)` will return `0.01779624378877313`.
If you need to extract the rate for some reason, you can get the rate by calling `FinanceModels.rate(...)`. Using the above example, `FinanceModels.rate(z)` will return `0.01779624378877313`.

```@index
```

```@autodocs
Modules = [Yields]
Modules = [FinanceModels]
```
Loading
Loading