Skip to content

Commit

Permalink
separate derivs, add specific test, update parameters and example (#52)
Browse files Browse the repository at this point in the history
* separate derivs, add specific test

* fix function name to be in correct order

* Tests Passing

* compat bound

* upate version

* min Julia Version
  • Loading branch information
alecloudenback authored Jun 22, 2024
1 parent b2e10bf commit 3469044
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
fail-fast: false
matrix:
version:
- '1.9'
- '1.10'
- '1'
os:
- ubuntu-latest
Expand Down
16 changes: 8 additions & 8 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
name = "EconomicScenarioGenerators"
uuid = "1d18cbdc-9ca7-45fd-a8b2-b9434f9145be"
authors = ["Alec Loudenback <alecloudenback@gmail.com> and contributors"]
version = "0.6.1"

[weakdeps]
FinanceModels = "77f2ae65-bdde-421f-ae9d-22f1af19dd76"
version = "0.7.0"

[deps]
Copulas = "ae264745-0b69-425e-9d9d-cf662c5eec93"
Expand All @@ -14,17 +11,20 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Transducers = "28d57a85-8fef-5791-bfe6-a80928e7c999"

[weakdeps]
FinanceModels = "77f2ae65-bdde-421f-ae9d-22f1af19dd76"

[extensions]
FinanceModelsExt = "FinanceModels"

[compat]
Copulas = "0.1"
FinanceCore = "2"
FinanceModels = "4 - 4.7"
Transducers = "0.4"
Distributions = "0.25"
FinanceCore = "2"
FinanceModels = "4.9"
ForwardDiff = "^0.10"
julia = "1.9"
Transducers = "0.4"
julia = "1.10"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
43 changes: 20 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ YieldCurve(s)

```

will produce a yield curve object:
will produce a yield curve object (if `UnicodePlots.jl` has also been imported):

```julia-repl
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀Yield Curve (FinanceModels.Yield.Spline)⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
Expand Down Expand Up @@ -102,24 +102,22 @@ Construct a yield curve and use that as the arbitrage-free forward curve within

```julia
using FinanceModels, EconomicScenarioGenerators
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 = FinanceModels.fit(
Spline.Cubic(),
CMTYield.(rates,mats),
Fit.Bootstrap()
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]
c = FinanceModels.fit(
FinanceModels.Spline.Cubic(),
FinanceModels.ZCBYield.(rates, mats),
FinanceModels.Fit.Bootstrap()
)

m = HullWhite(2.0, 0.025, c)

m = HullWhite(.1,.002,curve) # a, σ, curve
s = EconomicScenarioGenerators.ScenarioGenerator(
0.01, # timestep
30.0, # projection horizon
m
)

s = ScenarioGenerator(
1/12, # timestep
30., # projection horizon
m, # model
)
```

Create 1000 yield curves from the scenario generator:
Expand All @@ -132,22 +130,21 @@ curves = [YieldCurve(s) for i in 1:n]
Plot the result:
```julia
using Plots
using CairoMakie

times = 1:30
p=plot(title="EconomicScenarioGenerators.jl Hull White Model")

fig = Figure()
axis = Axis(fig[1,1],title="EconomicScenarioGenerators.jl Hull White Model",xlabel="time",ylabel="rate")
# plot the zero rates
for d in curves
plot!(p,times,rate.(zero.(d,times)),alpha=0.2,label="")
lines!(axis,times,rate.(zero.(d,times)),alpha=0.1,label="")
end

plot!(times,rate.(zero.(curve,times)),line=(:black, 5), label="Given Yield Curve")
p

lines!(axis,times,rate.(zero.(c,times)),color=:black,linewidth=7)
fig
```

![image](https://user-images.githubusercontent.com/711879/182291819-66a0fa9e-7aab-4e52-b434-58494257d005.svg)
![image](https://github.com/JuliaActuary/EconomicScenarioGenerators.jl/assets/711879/09ef7136-30bf-44cf-865c-987d0df92a4a)

### Equity Model Examples

Expand Down
4 changes: 1 addition & 3 deletions ext/FinanceModelsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ function ESG.θ(M::ESG.HullWhite{T}, time, timestep) where {T<:Union{FinanceMode
# https://quant.stackexchange.com/questions/8724/how-to-calibrate-hull-white-from-zero-curve
# https://mdpi-res.com/d_attachment/mathematics/mathematics-08-01719/article_deploy/mathematics-08-01719-v2.pdf?version=1603181408
a = M.a
f(t) = log(FinanceCore.discount(M.curve, t[1]))
δf = -only(ForwardDiff.hessian(f, [time]))::Float64
f_t = -only(ForwardDiff.gradient(f, [time]))::Float64
δf, f_t = ESG.__δf(M, time)

return δf + f_t * a + M.σ^2 / (2 * a) * (1 - exp(-2 * a * time))

Expand Down
11 changes: 10 additions & 1 deletion src/interest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ end
# See FinanceModels.jl for HullWhite with a YieldCurve defining theta

__initial_value(m::HullWhite, timestep) = FinanceCore.forward(m.curve, 0.0, timestep)
__initial_value(m::HullWhite{T}, timestep) where {T<:Real} = m.curve

# how would HullWhite be constructed if not giving it a curve?
function nextvalue(M::HullWhite{T}, prior, time, timestep, variate) where {T}
Expand All @@ -170,8 +171,16 @@ function θ(M::HullWhite{T}, time, timestep) where {T<:Real}
# https://quant.stackexchange.com/questions/8724/how-to-calibrate-hull-white-from-zero-curve
a = M.a
δf = 0
f_t = M.θ
f_t = M.curve

return δf + f_t * a + M.σ^2 / (2 * a) * (1 - exp(-2 * a * time))

end

function __δf(model, time)
f(t) = log(FinanceCore.discount(model.curve, t[1]))
δf = -only(ForwardDiff.hessian(f, [time]))::Float64
f_t = -only(ForwardDiff.gradient(f, [time]))::Float64
# @show time, f(time) / time, f_t, δf, f(time) / time + f_t
return δf, f_t
end
4 changes: 2 additions & 2 deletions test/Correlated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
Fit.Bootstrap()
)

m = HullWhite(0.1, 0.01, c)
m = HullWhite(2.0, 0.01, c)

s = ScenarioGenerator(
0.1, # timestep
Expand Down Expand Up @@ -142,7 +142,7 @@
CMTYield.(rates, mats),
Fit.Bootstrap())

m = HullWhite(0.1, 0.01, c)
m = HullWhite(2.0, 0.01, c)

s = ScenarioGenerator(
0.1, # timestep
Expand Down
1 change: 0 additions & 1 deletion test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[deps]
Copulas = "ae264745-0b69-425e-9d9d-cf662c5eec93"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
EconomicScenarioGenerators = "1d18cbdc-9ca7-45fd-a8b2-b9434f9145be"
FinanceCore = "b9b1ffdd-6612-4b69-8227-7663be06e089"
FinanceModels = "77f2ae65-bdde-421f-ae9d-22f1af19dd76"
HypothesisTests = "09f84164-cd44-5f33-b23f-e6b0d136a0d5"
Expand Down
58 changes: 51 additions & 7 deletions test/interest.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@
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]
c = FinanceModels.fit(
FinanceModels.Spline.Quadratic(),
FinanceModels.CMTYield.(rates, mats),
FinanceModels.Spline.Cubic(),
FinanceModels.ZCBYield.(rates, mats),
FinanceModels.Fit.Bootstrap()
)

m = HullWhite(0.1, 0.001, c)
m = HullWhite(2.0, 0.01, c)

s = ScenarioGenerator(
1.0, # timestep
Expand All @@ -95,14 +95,14 @@


s = EconomicScenarioGenerators.ScenarioGenerator(
0.05, # timestep
0.01, # timestep
30.0, # projection horizon
m,
StableRNG(1)
)

v = collect(s)
@test length(v) == 601
@test length(v) == 3001

@test YieldCurve(s) isa FinanceModels.Yield.AbstractYieldModel

Expand All @@ -119,7 +119,7 @@

@testset "with Rate" begin
c = FinanceCore.Continuous(0.03)
m = HullWhite(0.1, 0.001, c)
m = HullWhite(2.0, 0.001, c)

s = ScenarioGenerator(
1.0, # timestep
Expand Down Expand Up @@ -152,8 +152,52 @@
end

end
end
@testset "constant derivative" begin

import FinanceModels: AbstractYieldModel, discount

# a yield curve where the rate of change of the instantaneous forward is constant
struct ConstDeriv <: FinanceModels.Yield.AbstractYieldModel
d::Float64
initial::Float64
end

FinanceCore.discount(c::ConstDeriv, time) = exp(-(time^2 * c.d) / 2 - c.initial * time)


m = HullWhite(0.1, 0.001, ConstDeriv(0.01, 0.02))
a, b = EconomicScenarioGenerators.__δf(m, 1)
@test a 0.01
@test b 0.02 + 0.01 * 1
a, b = EconomicScenarioGenerators.__δf(m, 2)
@test a 0.01
@test b 0.02 + 0.01 * 2

end

@testset "other functional forms" begin

# discount = exp(-time^power/denom)
struct Power <: FinanceModels.Yield.AbstractYieldModel
p::Float64
denom::Float64
end

FinanceCore.discount(c::Power, time) = exp(-(time)^c.p / c.denom)

m = HullWhite(0.1, 0.001, Power(2, 10))
a, b = EconomicScenarioGenerators.__δf(m, 1)
@test a 1 / 5
@test b 1 / 5
a, b = EconomicScenarioGenerators.__δf(m, 2)
@test a 1 / 5
@test b 2 / 5




end
end


end

1 comment on commit 3469044

@alecloudenback
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juliarefistrator register

Please sign in to comment.