Skip to content

Commit

Permalink
migrate from BSplineKit to DataInterpolations, provide `PolynomialSpl…
Browse files Browse the repository at this point in the history
…ine`
  • Loading branch information
alecloudenback committed Apr 11, 2024
1 parent b58fce9 commit 185bd76
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 21 deletions.
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name = "FinanceModels"
uuid = "77f2ae65-bdde-421f-ae9d-22f1af19dd76"
authors = ["Alec Loudenback <[email protected]> and contributors"]
version = "4.7.0"
version = "4.8.0"

[deps]
AccessibleOptimization = "d88a00a0-4a21-4fe4-a515-e2123c37b885"
Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697"
BSplineKit = "093aae92-e908-43d7-9660-e50ee39d5a0a"
DataInterpolations = "82cc6244-b520-54b8-b5a6-8a565e85f1d0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
FinanceCore = "b9b1ffdd-6612-4b69-8227-7663be06e089"
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
Expand All @@ -29,7 +29,7 @@ FinanceModelsMakieCoreExt = "MakieCore"
[compat]
AccessibleOptimization = "^0.1.1"
Accessors = "^0.1"
BSplineKit = "^0.16, 0.17"
DataInterpolations = "^4.7.1"
Dates = "^1.6"
FinanceCore = "^2.1"
IntervalSets = "^0.7"
Expand Down
2 changes: 1 addition & 1 deletion src/Contract.jl
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ coupon_times(b::AbstractBond) = coupon_times(b.maturity, b.frequency.frequency)

for op = (:ZCBPrice, :ZCBYield, :ParYield, :ParSwapYield, :CMTYield, :ForwardYield)
eval(quote
$op(x::Vector; kwargs...) = $op.(x, eachindex(x); kwargs...)
$op(x::Vector; kwargs...) = $op.(x, float.(eachindex(x)); kwargs...)
end)
end

Expand Down
2 changes: 1 addition & 1 deletion src/FinanceModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using AccessibleOptimization
using Accessors
using LinearAlgebra
using Transducers
import BSplineKit
import DataInterpolations
import UnicodePlots
using Transducers: @next, complete, __foldl__, asfoldable
import SpecialFunctions
Expand Down
2 changes: 1 addition & 1 deletion src/fit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ function fit(mod0, quotes, method::F=Fit.Loss(x -> x^2);

end

function fit(mod0::Spline.BSpline, quotes, method::Fit.Bootstrap)
function fit(mod0::T, quotes, method::Fit.Bootstrap) where {T<:Spline.SplineCurve}
discount_vector = [0.0]
times = [maturity(quotes[1])]

Expand Down
17 changes: 11 additions & 6 deletions src/model/Spline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,28 @@ Spline is a module which offers various degree splines used for fitting or boots
Available methods:
- `Spline.BSpline(n)` where n is the nth order. A spline function of order n is a piecewise polynomial function of degree n − 1. This means that, e.g., cubic polynomial is a fourth degree B-Spline.
- `Spline.BSpline(n)` where n is the nth order. A nth-order B-Spline is analagous to an (n-1)th order polynomial spline. That is, a 3rd/4th order BSpline is very similar to a quadratic/cubic spline respectively. BSplines are global in that a change in one point affects the entire spline (though the spline still passes through the other given points still).
- `Spline.PolynomialSpline(n)` where n is the nth order.
This object is not a fitted spline itself, rather it is a placeholder object which will be a spline representing the data only after using within [`fit`](@ref FinanceModels.fit-Union{Tuple{F}, Tuple{Any, Any}, Tuple{Any, Any, F}} where F<:FinanceModels.Fit.Loss).
and convienience methods which create a `Spline.BSpline` object of the appropriate order.
- `Spline.Linear()`
- `Spline.Quadratic()`
- `Spline.Cubic()`
- `Spline.Linear()` equals `BSpline(2)`
- `Spline.Quadratic()` equals `BSpline(3)`
- `Spline.Cubic()` equals `BSpline(4)`
"""
module Spline
import ..FinanceCore
import ..BSplineKit
import ..AbstractModel

abstract type SplineCurve end

struct BSpline
struct PolynomialSpline <: SplineCurve
order::Int
end

struct BSpline <: SplineCurve
order::Int
end

Expand Down
30 changes: 23 additions & 7 deletions src/model/Yield.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Yield
import ..AbstractModel
import ..FinanceCore
import ..Spline as Sp
import ..BSplineKit
import ..DataInterpolations
import UnicodePlots
import ..Bond: coupon_times

Expand Down Expand Up @@ -33,8 +33,8 @@ Constant() = Constant(0.0)
FinanceCore.discount(c::Constant, t) = FinanceCore.discount(c.rate, t)

# used as the object which gets optmized before finally returning a completed spline
struct IntermediateYieldCurve{U,V} <: AbstractYieldModel
b::Sp.BSpline
struct IntermediateYieldCurve{T<:Sp.SplineCurve,U,V} <: AbstractYieldModel
b::T
xs::Vector{U}
ys::Vector{V} # here, ys are the discount factors
end
Expand All @@ -60,12 +60,28 @@ function FinanceCore.discount(c::Spline, time)
end

function Spline(b::Sp.BSpline, xs, ys)
order = min(length(xs), b.order) # in case the length of xs is less than the spline order
int = BSplineKit.interpolate(xs, ys, BSplineKit.BSplineOrder(order))
return Spline(BSplineKit.extrapolate(int, BSplineKit.Smooth()))
order = min(length(xs) - 1, b.order) # in case the length of xs is less than the spline order
xs = float.(xs)
knot_type = if length(xs) < 3
:Uniform
else
:Average
end

return Spline(DataInterpolations.BSplineInterpolation(ys, xs, order, :Uniform, knot_type; extrapolate=true))
end

function Spline(b::Sp.PolynomialSpline, xs, ys)
order = min(length(xs) - 1, b.order) # in case the length of xs is less than the spline order
if order == 1
return Spline(DataInterpolations.LinearInterpolation(ys, xs; extrapolate=true))
elseif order == 2
return Spline(DataInterpolations.QuadraticSpline(ys, xs; extrapolate=true))
else
return Spline(DataInterpolations.CubicSpline(ys, xs; extrapolate=true))
end
end


include("Yield/SmithWilson.jl")
include("Yield/NelsonSiegelSvensson.jl")

Expand Down
15 changes: 13 additions & 2 deletions test/Yield.jl
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,19 @@ end
maturity = [0.5, 1.0, 1.5, 2.0]
zero = [5.0, 5.8, 6.4, 6.8] ./ 100
zs = ZCBYield.(zero, maturity)
@testset "$i" for (i, curve) in enumerate([fit(Spline.Cubic(), zs, Fit.Bootstrap()), fit(Spline.Linear(), zs, Fit.Bootstrap()), fit(Spline.Quadratic(), zs, Fit.Bootstrap()), fit(Spline.BSpline(5), zs, Fit.Bootstrap())])

variants = [
Spline.Cubic(),
Spline.Linear(),
Spline.Quadratic(),
Spline.BSpline(5),
Spline.BSpline(3),
Spline.BSpline(1),
Spline.PolynomialSpline(1),
Spline.PolynomialSpline(2),
Spline.PolynomialSpline(3),
]
@testset "Constructor $i" for (i, m) in enumerate(variants)
curve = fit(m, zs, Fit.Bootstrap())
@test discount(curve, 1) 1 / 1.058
@test discount(curve, 1.5) 1 / 1.064^1.5
@test discount(curve, 2) 1 / 1.068^2
Expand Down

0 comments on commit 185bd76

Please sign in to comment.