This re-write accomplishes three primary things:
- Provide a composable set of contracts and
Quotes
- Those contracts, when combined with a model produce a
Cashflow
via a flexibly definedProjection
- models can be
fit
with a new unified API:fit(model_type,quotes,fit_method)
You should remove Yields
from your project's dependencies and add FinanceModels
instead. (link to Pkg documentation on how to do this)
Previously, the API pattern was, e.g.:
model = Yields.Par(SmitWilson(...), rates,timepoints)
Now, follow the pattern of:
- Define the quotes you want to fit the model to
fit
the model to those quotes
Example:
quotes = ParYield.(rates,timepoints)
model = fit(SmithWilson(),quotes)
Previously the kind of contract, the implied quotes, the type of model, and how the fitting process worked were all combined into a single call (Yields.Par
). This minimized the amount of code needed to construct a yield curve, but left it fairly cumbersome to extend the package. For example, for every new yield curve model, methods for Par
, CMT
, OIS
, Zero
, ... had to be defined. Additionally, all of the inputs needed to be yields - specifying a price was not available as an argument to fit.
With the new design of the package, creating a completely new model is much easier, as only the model itself and the valuation primitives need to be defined. For example, defining a new yield curve type that works to value contracts instrument quotes only requires defining the discount
method. To allow the model to be fit
requires only defining a default set of parameters to optimize with __default_optic
:
using FinanceModels, FinanceCore
using AccessibleOptimization
using IntervalSets
struct ABDiscountLine{A} <: FinanceModels.Yield.AbstractYieldModel
a::A
b::A
end
# define the default constructor for convenience
ABDiscountLine() = ABDiscountLine(0.,0.)
function FinanceCore.discount(m::ABDiscountLine,t)
#discount rate is approximated by a straight lined, floored at 0.0 and capped at 1.0
clamp(m.a*t + m.b, 0.0,1.0)
end
# `@optic` indicates what in our model variables needs to be updated (from AccessibleOptimization.jl)
# `-1.0 .. 1.0` says to bound the search from negative to positive one (from IntervalSets.jl)
FinanceModels.__default_optic(m::ABDiscountLine) = OptArgs([
@optic(_.a) => -1.0 .. 1.0,
@optic(_.b) => -1.0 .. 1.0,
]...)
quotes = ZCBPrice([0.9, 0.8, 0.7,0.6])
m = fit(ABDiscountLine(),quotes)