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

Add unittests to increase test coverage #94

Merged
merged 1 commit into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
56 changes: 56 additions & 0 deletions test/unittests/analytics/covariances.jl
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ using Test
Dict{String, DiffFusion.FixingEntry}(),
)

struct NoModel <: DiffFusion.Model end # dummy model for testing

@testset "Test scaling vector calculation" begin
ch_full = get_correlation("Std")
mdl = hybrid_model(ch_full)
Expand All @@ -173,6 +175,7 @@ using Test
#
# test constraints
@test_throws ErrorException DiffFusion.reference_rate_scaling("NoKey", 1.0, mdl, ctx)
@test_throws ErrorException DiffFusion.reference_rate_scaling("EUR", 1.0, NoModel(), ctx)
@test_throws AssertionError DiffFusion.reference_rate_scaling("EUR", -1.0, mdl, ctx)
@test_throws AssertionError DiffFusion.reference_rate_scaling("USD", 0.0, mdl, ctx)
@test_throws AssertionError DiffFusion.reference_rate_scaling("USD-EUR", 1.0, mdl, ctx)
Expand Down Expand Up @@ -363,4 +366,57 @@ using Test
# display(C)
end

@testset "Test degenerated volatility and correlation calculation" begin
ch_full = get_correlation("Std")
times = [ 0. ]
#
hjm_eur = DiffFusion.gaussian_hjm_model(
"EUR",
DiffFusion.flat_parameter([ 1., 10., 20. ]), # delta
DiffFusion.flat_parameter([ 0.01, 0.10, 0.30 ]), # chi
DiffFusion.backward_flat_volatility("",times,[ 0. 0. 0. ]' * 1.0e-4), # sigma
ch_full,
nothing,
)
fx_usd_eur = DiffFusion.lognormal_asset_model(
"USD-EUR",
DiffFusion.flat_volatility("", 0.0),
ch_full,
nothing,
)
hjm_usd = DiffFusion.gaussian_hjm_model(
"USD",
DiffFusion.flat_parameter([ 1., 10., 20. ]), # delta
DiffFusion.flat_parameter([ 0.01, 0.10, 0.30 ]), # chi
DiffFusion.backward_flat_volatility("",times,[ 0. 0. 0. ]' * 1.0e-4), # sigma
ch_full,
fx_usd_eur,
)
#
mdl = DiffFusion.simple_model("Std", [ hjm_eur, fx_usd_eur, hjm_usd])
#
dt = 0.25
(v, C) = DiffFusion.reference_rate_volatility_and_correlation(
[
("EUR", 1.0),
("EUR", 5.0),
("EUR", 10.0),
("USD-EUR", 0.0),
],
ctx, mdl, ch_full, 0.0, dt
)
#
v_ref = zeros(4)
C_ref = [
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
]
@test v == v_ref
@test C == C_ref
# display(v)
# display(C)
end

end
65 changes: 63 additions & 2 deletions test/unittests/analytics/valuations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ using ForwardDiff
sim = DiffFusion.simple_simulation(fx_model, ch, times, n_paths, with_progress_bar = false)
path = DiffFusion.path(sim, ts_list, context, DiffFusion.LinearPathInterpolation)

sim_func(model, ch) = DiffFusion.simple_simulation(model, ch, times, n_paths, with_progress_bar = false)
make_regression(C, O) = DiffFusion.polynomial_regression(C, O, 1)

@testset "Delta calculation" begin
@info "Start testing AD Deltas..."
Expand Down Expand Up @@ -76,7 +78,6 @@ using ForwardDiff
@testset "Vega calculation" begin
@info "Start testing AD Vegas..."
model = DiffFusion.simple_model("Std", [fx_model])
sim_func(model, ch) = DiffFusion.simple_simulation(model, ch, times, n_paths, with_progress_bar = false)
#
payoffs = [ DiffFusion.Asset(2.0, "EUR-USD")]
model_price = DiffFusion.model_price(payoffs, path, nothing, "USD")
Expand All @@ -96,4 +97,64 @@ using ForwardDiff
# println(g1)
end

end
@testset "Zero model price and delta/vega calculation" begin
# also capture case with non-trivial correlation
ch = DiffFusion.correlation_holder("Two")
DiffFusion.set_correlation!(ch, "EUR-USD_x", "GBP-USD_x", 0.3)
sigma_fx = DiffFusion.flat_volatility("EUR-USD", 0.15)
fx_model = DiffFusion.lognormal_asset_model("EUR-USD", sigma_fx, ch, nothing)
sim = DiffFusion.simple_simulation(fx_model, ch, times, n_paths, with_progress_bar = false)
path = DiffFusion.path(sim, ts_list, context, DiffFusion.LinearPathInterpolation)
#
payoffs = [ ]
model_price = DiffFusion.model_price(payoffs, path, nothing, "USD")
@test model_price == 0.0
#
@info "Testing Zero AD Deltas..."
#
(v, g) = DiffFusion.model_price_and_deltas(payoffs, path, nothing, "USD")
@test v == model_price
#
model_price = DiffFusion.model_price(payoffs, path, nothing, nothing)
(v, g) = DiffFusion.model_price_and_deltas(payoffs, path, nothing, nothing)
@test v == model_price
#
model_price = DiffFusion.model_price(payoffs, path, nothing, "USD")
(v1, g1, l1) = DiffFusion.model_price_and_deltas_vector(payoffs, path, nothing, "USD", Zygote)
(v2, g2, l2) = DiffFusion.model_price_and_deltas_vector(payoffs, path, nothing, "USD", ForwardDiff)
(v3, g3, l3) = DiffFusion.model_price_and_deltas_vector(payoffs, path, nothing, "USD", FiniteDifferences)
@test v1 == model_price
@test v2 == model_price
@test v2 == model_price
# @test isapprox(g1, g2, atol=1.0e-12)
# @test isapprox(g2, g3, atol=1.0e-10)
#
model_price = DiffFusion.model_price(payoffs, path, nothing, nothing)
(v1, g1, l1) = DiffFusion.model_price_and_deltas_vector(payoffs, path, nothing, nothing, Zygote)
(v2, g2, l2) = DiffFusion.model_price_and_deltas_vector(payoffs, path, nothing, nothing, ForwardDiff)
(v3, g3, l3) = DiffFusion.model_price_and_deltas_vector(payoffs, path, nothing, nothing, FiniteDifferences)
@test v1 == model_price
@test v2 == model_price
@test v3 == model_price
# @test isapprox(g1, g2, atol=1.0e-12)
# @test isapprox(g2, g3, atol=1.0e-9)
#
@info "Testing Zero AD Vegas..."
#
model = DiffFusion.simple_model("Std", [fx_model])
#
(v, g) = DiffFusion.model_price_and_vegas(payoffs, model, sim_func, ts_list, context, nothing, "USD")
@test v == model_price
#
model_price = DiffFusion.model_price(payoffs, path, nothing, "USD")
(v1, g1, l1) = DiffFusion.model_price_and_vegas_vector(payoffs, model, sim_func, ts_list, context, nothing, "USD", Zygote)
(v2, g2, l2) = DiffFusion.model_price_and_vegas_vector(payoffs, model, sim_func, ts_list, context, nothing, "USD", ForwardDiff)
(v3, g3, l3) = DiffFusion.model_price_and_vegas_vector(payoffs, model, sim_func, ts_list, context, nothing, "USD", FiniteDifferences)
@test v1 == model_price
@test v2 == model_price
@test v3 == model_price
# @test isapprox(g1, g2, atol=1.0e-12)
# @test isapprox(g2, g3, atol=1.0e-10)
end

end
50 changes: 49 additions & 1 deletion test/unittests/paths/path.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ end
# valuation context with deterministic dividend yield

context = DiffFusion.Context("Std",
DiffFusion.NumeraireEntry("USD", "USD", Dict(_empty_key => "USD")),
DiffFusion.NumeraireEntry("USD", "USD", Dict(_empty_key => "USD", "OIS" => "USD")),
Dict{String, DiffFusion.RatesEntry}([
("USD", DiffFusion.RatesEntry("USD", "USD", Dict(_empty_key => "USD", "OIS" => "USD", "NO" => "ZERO"))),
("EUR", DiffFusion.RatesEntry("EUR", "EUR", Dict(_empty_key => "EUR", "NO" => "ZERO"))),
Expand Down Expand Up @@ -239,6 +239,8 @@ end
p = DiffFusion.path(sim, ts, context)
t = 2.0
@test isapprox(DiffFusion.numeraire(p, t, "USD"), exp(1.0 + 0.03*t) * ones(5), atol=1.0e-15)
@test isapprox(DiffFusion.numeraire(p, t, "USD:OIS"), exp(1.0 + 0.03*t) * ones(5), atol=1.0e-15)
@test isapprox(DiffFusion.numeraire(p, t, "USD:OIS-OIS"), exp(1.0) * ones(5), atol=1.0e-15)
#
@test isapprox(DiffFusion.bank_account(p, t, "USD"), exp(1.0 + 0.03*t) * ones(5), atol=1.0e-15)
@test isapprox(DiffFusion.bank_account(p, t, "EUR"), exp(1.0 + 0.02*t) * ones(5), atol=1.0e-15)
Expand Down Expand Up @@ -426,4 +428,50 @@ end
@test DiffFusion.forward_rate_variance(p, 1.0, 2.0, 2.0, 3.0, "USD") == zeros(1)
@test DiffFusion.asset_variance(p, 1.0, 2.0, "EUR-USD") == zeros(1)
end

@testset "Forward asset special cases." begin
t = 2.0
T = 5.0
#
context = DiffFusion.Context("Std",
DiffFusion.NumeraireEntry("USD", "USD", Dict(_empty_key => "USD")),
Dict{String, DiffFusion.RatesEntry}([
("USD", DiffFusion.RatesEntry("USD", "USD", Dict(_empty_key => "USD"))),
("EUR", DiffFusion.RatesEntry("EUR", "EUR", Dict(_empty_key => "EUR"))),
#
("USD_NULL", DiffFusion.RatesEntry("USD", nothing, Dict(_empty_key => "USD"))),
("EUR_NULL", DiffFusion.RatesEntry("EUR", nothing, Dict(_empty_key => "EUR"))),
]),
Dict{String, DiffFusion.AssetEntry}([
("DK_MODEL", DiffFusion.AssetEntry("EUR-USD", nothing, "USD", "EUR", "EUR-USD", Dict(_empty_key => "USD"), Dict(_empty_key => "EUR"))),
("ST_DIV_1", DiffFusion.AssetEntry("EUR-USD", nothing, nothing, "EUR", "EUR-USD", Dict(_empty_key => "USD"), Dict(_empty_key => "EUR"))),
("ST_DIV_2", DiffFusion.AssetEntry("EUR-USD", "EUR-USD", nothing, "EUR", "EUR-USD", Dict(_empty_key => "USD"), Dict(_empty_key => "EUR"))),
("RATES", DiffFusion.AssetEntry("EUR-USD", nothing, "USD", nothing, "EUR-USD", Dict(_empty_key => "USD"), Dict(_empty_key => "EUR"))),
]),
Dict{String, DiffFusion.ForwardIndexEntry}(),
Dict{String, DiffFusion.FutureIndexEntry}(),
Dict{String, DiffFusion.FixingEntry}(),
)
p = DiffFusion.path(sim, ts, context)
#
S_t = DiffFusion.asset(p, t, "DK_MODEL")
P_d = DiffFusion.zero_bond(p, t, T, "USD")
P_f = DiffFusion.zero_bond(p, t, T, "EUR")
@test isapprox(DiffFusion.forward_asset(p, t, T, "DK_MODEL"), S_t .* P_f ./ P_d, atol=5.0e-15)
#
S_t = DiffFusion.asset(p, t, "ST_DIV_1")
P_d = DiffFusion.zero_bond(p, t, T, "USD_NULL")
P_f = DiffFusion.zero_bond(p, t, T, "EUR")
@test isapprox(DiffFusion.forward_asset(p, t, T, "ST_DIV_1"), S_t .* P_f ./ P_d, atol=5.0e-15)
#
S_t = DiffFusion.asset(p, t, "ST_DIV_2")
P_d = DiffFusion.zero_bond(p, t, T, "USD_NULL")
P_f = DiffFusion.zero_bond(p, t, T, "EUR")
@test isapprox(DiffFusion.forward_asset(p, t, T, "ST_DIV_2"), S_t .* P_f ./ P_d, atol=5.0e-15)
#
S_t = DiffFusion.asset(p, t, "RATES")
P_d = DiffFusion.zero_bond(p, t, T, "USD")
P_f = DiffFusion.zero_bond(p, t, T, "EUR_NULL")
@test isapprox(DiffFusion.forward_asset(p, t, T, "RATES"), S_t .* P_f ./ P_d, atol=5.0e-15)
end
end
21 changes: 21 additions & 0 deletions test/unittests/products/rates_coupons.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ using Test
@test string(DiffFusion.amount(C)) == "(Idx(EURIBOR, -0.50) + 0.0100) * 1.0000"
end

@testset "SimpleRate option test" begin
C = DiffFusion.SimpleRateCoupon(1.8, 2.0, 3.0, 3.2, 1.0, "EUR6M", nothing, nothing)
O = DiffFusion.OptionletCoupon(C, 0.01, +1.0) # expiry_time from CompoundedRateCoupon
@test DiffFusion.pay_time(O) == 3.2
@test DiffFusion.year_fraction(O) == 1.0
@test string(DiffFusion.amount(O)) == "Max(1.0000 * (L(EUR6M, 1.80; 2.00, 3.00) - 0.0100), 0.0000) * 1.0000"
@test string(DiffFusion.expected_amount(O, 0.5)) == "Caplet(L(EUR6M, 0.50; 2.00, 3.00), 0.0100; 1.80) * 1.0000"
@test string(DiffFusion.expected_amount(O, 1.0)) == "Caplet(L(EUR6M, 1.00; 2.00, 3.00), 0.0100; 1.80) * 1.0000"
@test string(DiffFusion.expected_amount(O, 2.5)) == "Max(1.0000 * (L(EUR6M, 1.80; 2.00, 3.00) - 0.0100), 0.0000) * 1.0000"
@test string(DiffFusion.expected_amount(O, 3.0)) == "Max(1.0000 * (L(EUR6M, 1.80; 2.00, 3.00) - 0.0100), 0.0000) * 1.0000"
# println(string(DiffFusion.amount(O)))
# println(string(DiffFusion.expected_amount(O, 0.0)))
end

@testset "CompoundedRateCoupon test" begin
period_times = 1.0:0.1:2.0
period_year_fractions = period_times[2:end] - period_times[1:end-1]
Expand Down Expand Up @@ -88,6 +102,13 @@ using Test
@test string(DiffFusion.expected_amount(C, 0.05)) == string(DiffFusion.amount(C))
@test string(DiffFusion.expected_amount(C, 0.1)) == string(DiffFusion.amount(C))
@test string(DiffFusion.expected_amount(C, 0.2)) == string(DiffFusion.amount(C))
#
period_times = [-2.0, -1.5, -1.0]
period_year_fractions = [ 0.5, 0.5 ]
C = DiffFusion.CompoundedRateCoupon(period_times, period_year_fractions, period_times[end], "USD:SOFR", "SOFR", 0.02)
@test string(DiffFusion.amount(C)) == "((((1.0000 + Idx(SOFR, -2.00) * 0.5000) * (1.0000 + Idx(SOFR, -1.50) * 0.5000) - 1.0000) / 1.0000) + 0.0200) * 1.0000"
@test string(DiffFusion.expected_amount(C, 0.0)) == string(DiffFusion.amount(C))
#
# println(string(DiffFusion.amount(C)))
# println(string(DiffFusion.expected_amount(C, 0.0)))
end
Expand Down
34 changes: 34 additions & 0 deletions test/unittests/serialisation/rebuild_models.jl
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ using Test
for (a, b) in zip(keys(d), ["EUR", "Std", "Full", "EUR-USD", "SXE50-EUR", "USD"])
@test a == b
end
# Simple 1F model
delta = DiffFusion.flat_parameter([ 1., ])
chi = DiffFusion.flat_parameter([ 0.01, ])
times = [ 0. ]
values = [ 50. ]' * 1.0e-4
sigma_f = DiffFusion.backward_flat_volatility("USD", times, values)
hjm_model = DiffFusion.gaussian_hjm_model("md/USD", delta, chi, sigma_f, nothing, nothing)
d = DiffFusion.model_parameters(hjm_model)
@test d["md/USD"]["correlation_holder"] == nothing # this is what's different in this test
end

@testset "Re-build models" begin
Expand Down Expand Up @@ -109,6 +118,17 @@ using Test
model_dict = Dict{String, Any}()
model = DiffFusion.build_model(DiffFusion.alias(full_model), param_dict, model_dict)
@test string(model) == string(full_model)
# Simple 1F model w/o correlation
delta = DiffFusion.flat_parameter([ 1., ])
chi = DiffFusion.flat_parameter([ 0.01, ])
times = [ 0. ]
values = [ 50. ]' * 1.0e-4
sigma_f = DiffFusion.backward_flat_volatility("USD", times, values)
hjm_model = DiffFusion.gaussian_hjm_model("md/USD", delta, chi, sigma_f, nothing, nothing)
param_dict = DiffFusion.model_parameters(hjm_model)
model_dict = Dict{String, Any}()
model = DiffFusion.build_model(DiffFusion.alias(hjm_model), param_dict, model_dict)
@test string(model) == string(hjm_model)
end


Expand Down Expand Up @@ -209,6 +229,20 @@ using Test
m_dict = Dict{String, Any}()
m1 = DiffFusion.build_model(m.alias, p_dict, m_dict)
@test string(m1) == string(m)
#
# Re-build with quanto model
quanto_model = DiffFusion.lognormal_asset_model("USD-GBP", σ, ch_full, nothing)
m = DiffFusion.cev_asset_model("EUR-USD", σ, γ, ch_full, quanto_model)
d = DiffFusion.model_parameters(m)
(l, v) = DiffFusion.model_volatility_values(m.alias, d)
p_dict = Dict{String, Any}( "Full" => ch_full, )
for k in keys(d)
p_dict[k] = d[k]
end
DiffFusion.model_parameters!(p_dict, l, v)
m_dict = Dict{String, Any}( "USD-GBP" => quanto_model, )
m1 = DiffFusion.build_model(m.alias, p_dict, m_dict)
@test string(m1) == string(m)
# println(l)
# println(d)
end
Expand Down
Loading