Migration Guide
v4 to v5
Yield curve + and - now operate in continuous zero-rate space
In v4, curve_a + curve_b added rates in whatever compounding convention the curves happened to use. In v5, + and - always work in continuous zero-rate (CZR) space, which is equivalent to multiplying/dividing discount factors:
# v5 behavior:
combined = curve_a + curve_b
discount(combined, t) == discount(curve_a, t) * discount(curve_b, t)This is the economically correct way to combine deflators — see Yield Curve Arithmetic for a full explanation.
What to check when upgrading: If your v4 code added curves whose rates were expressed in Periodic conventions, the combined discount factors will now differ by the cross-term. For small rates and short horizons the difference is minor, but it compounds over long projections (e.g. 10 bps/year for a 5% base + 2% spread).
ForwardYields renamed to ForwardYield
The plural ForwardYields has been renamed to ForwardYield for consistency with other singular type names (Yield.Constant, ZCBYield, etc.).
v3 to v4
Yields.jl is now FinanceModels.jl
This re-write accomplishes three primary things:
- Provide a composable set of contracts and
Quotes - Those contracts, when combined with a model produce a
Cashflowvia a flexibly definedProjection - models can be
fitwith a new unified API:fit(model_type,quotes,fit_method)
Migrating Code
Update Dependencies
You should remove Yields from your project's dependencies and add FinanceModels instead. (link to Pkg documentation on how to do this)
API Changes
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
fitthe model to those quotes
Example:
quotes = ParYield.(rates,timepoints)
model = fit(SmithWilson(),quotes)Details of changes
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 AccessibleModels
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 AccessibleModels.jl)
# `-1.0 .. 1.0` says to bound the search from negative to positive one (from IntervalSets.jl)
FinanceModels.__default_optic(m::ABDiscountLine) = (
@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)