diff --git a/src/models/rates/GaussianHjmModel.jl b/src/models/rates/GaussianHjmModel.jl index 8b9bd037..d9b34b31 100644 --- a/src/models/rates/GaussianHjmModel.jl +++ b/src/models/rates/GaussianHjmModel.jl @@ -39,6 +39,7 @@ end factor_alias::AbstractVector correlation_holder::Union{CorrelationHolder, Nothing} quanto_model::Union{AssetModel, Nothing} + scaling_type::BenchmarkTimesScaling end A Gaussian HJM model with piece-wise constant benchmark rate volatility and @@ -54,6 +55,7 @@ struct GaussianHjmModel <: SeparableHjmModel factor_alias::AbstractVector correlation_holder::Union{CorrelationHolder, Nothing} quanto_model::Union{AssetModel, Nothing} + scaling_type::BenchmarkTimesScaling end """ @@ -76,7 +78,7 @@ function gaussian_hjm_model( sigma_f::BackwardFlatVolatility, correlation_holder::Union{CorrelationHolder, Nothing}, quanto_model::Union{AssetModel, Nothing}, - scaling_type::BenchmarkTimesScaling = ForwardRateScaling, + scaling_type::BenchmarkTimesScaling = _default_benchmark_time_scaling, ) # Check inputs @assert length(delta()) > 0 @@ -117,7 +119,7 @@ function gaussian_hjm_model( y0 = y[:,:,k] end return GaussianHjmModel(alias, delta, chi, sigma_T, y, - state_alias, factor_alias, correlation_holder, quanto_model) + state_alias, factor_alias, correlation_holder, quanto_model, scaling_type) end """ diff --git a/src/models/rates/SeparableHjmModel.jl b/src/models/rates/SeparableHjmModel.jl index 6cc023df..face6c92 100644 --- a/src/models/rates/SeparableHjmModel.jl +++ b/src/models/rates/SeparableHjmModel.jl @@ -118,6 +118,14 @@ https://ssrn.com/abstract=4638188 for details. ) +""" + const _default_benchmark_time_scaling = ForwardRateScaling + +We specify a default value to allow for backward compatibility in +seialisation. +""" +const _default_benchmark_time_scaling = ForwardRateScaling + """ benchmark_times_scaling_forward_rate(chi::AbstractVector, delta::AbstractVector) diff --git a/src/serialisation/Models.jl b/src/serialisation/Models.jl index 87956ad2..cf95b4b1 100644 --- a/src/serialisation/Models.jl +++ b/src/serialisation/Models.jl @@ -7,6 +7,20 @@ Serialise model Context. serialise(o::Context) = serialise_struct(o) +""" + serialise(o::BenchmarkTimesScaling) + +Serialise a BenchmarkTimesScaling enumeration object. +""" +function serialise(o::BenchmarkTimesScaling) + d = OrderedDict{String, Any}() + d["typename"] = string(typeof(o)) + d["constructor"] = "BenchmarkTimesScaling" + d["enumeration"] = Integer(o) + return d +end + + """ serialise(o::GaussianHjmModel) @@ -30,6 +44,9 @@ function serialise(o::GaussianHjmModel) else d["quanto_model"] = serialise_key(o.quanto_model.alias) end + if o.scaling_type != _default_benchmark_time_scaling + d["scaling_type"] = serialise(o.scaling_type) + end return d end diff --git a/src/serialisation/RebuildModels.jl b/src/serialisation/RebuildModels.jl index 0efa19e8..237a167c 100644 --- a/src/serialisation/RebuildModels.jl +++ b/src/serialisation/RebuildModels.jl @@ -29,6 +29,7 @@ function model_parameters(m::GaussianHjmModel) else d["quanto_model"] = m.quanto_model.alias end + d["scaling_type"] = m.scaling_type # we add another dict layer to allow combining models and ts. return Dict(m.alias => d) end @@ -143,6 +144,7 @@ function build_model( m_dict["sigma_f"], ch, quanto_model, + m_dict["scaling_type"], ) end if m_dict["type"] == LognormalAssetModel diff --git a/test/unittests/serialisation/models.jl b/test/unittests/serialisation/models.jl index 3dda8831..baf26028 100644 --- a/test/unittests/serialisation/models.jl +++ b/test/unittests/serialisation/models.jl @@ -133,6 +133,94 @@ using YAML end end + @testset "GaussianHjmModel with BenchmarkTimesScaling (de-)serialisation." begin + models = setup_models(ch_full) + ref_dict = Dict( + "EUR-USD" => models[2], + "One" => ch_one, + "Full" => ch_full + ) + # + d = OrderedDict( + "typename" => "DiffFusion.GaussianHjmModel", + "constructor" => "gaussian_hjm_model", + "alias" => "USD", + "delta" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BackwardFlatParameter", + "constructor" => "BackwardFlatParameter", + "alias" => "", + "times" => [0.0], + "values" => [[1.0], [7.0], [15.0]], + ), + "chi" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BackwardFlatParameter", + "constructor" => "BackwardFlatParameter", + "alias" => "", + "times" => [0.0], + "values" => [[0.01], [0.1], [0.3]], + ), + "sigma_f" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BackwardFlatVolatility", + "constructor" => "BackwardFlatVolatility", + "alias" => "USD", + "times" => [0.0], + "values" => [[0.005], [0.006], [0.007]] + ), + "correlation_holder" => "{Full}", + "quanto_model" => "nothing", + "scaling_type" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BenchmarkTimesScaling", + "constructor" => "BenchmarkTimesScaling", + "enumeration" => 1, + ), + ) + o = DiffFusion.deserialise(d, ref_dict) + s = DiffFusion.serialise(o) + if VERSION >= v"1.7" # equality tests fail with Julia 1.6 + @test s == d + end + # + d = OrderedDict( + "typename" => "DiffFusion.GaussianHjmModel", + "constructor" => "gaussian_hjm_model", + "alias" => "EUR", + "delta" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BackwardFlatParameter", + "constructor" => "BackwardFlatParameter", + "alias" => "", + "times" => [0.0], + "values" => [[1.0], [10.0]], + ), + "chi" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BackwardFlatParameter", + "constructor" => "BackwardFlatParameter", + "alias" => "", + "times" => [0.0], + "values" => [[0.01], [0.15]], + ), + "sigma_f" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BackwardFlatVolatility", + "constructor" => "BackwardFlatVolatility", + "alias" => "EUR", + "times" => [0.0], + "values" => [[0.008], [0.009000000000000001]], + ), + "correlation_holder" => "{Full}", + "quanto_model" => "{EUR-USD}", + "quanto_model" => "nothing", + "scaling_type" => OrderedDict{String, Any}( + "typename" => "DiffFusion.BenchmarkTimesScaling", + "constructor" => "BenchmarkTimesScaling", + "enumeration" => 2, + ), + ) + o = DiffFusion.deserialise(d, ref_dict) + s = DiffFusion.serialise(o) + if VERSION >= v"1.7" # equality tests fail with Julia 1.6 + @test s == d + end + end + @testset "LognormalAssetModel (de-)serialisation." begin models = setup_models(ch_full) ref_dict = Dict( diff --git a/test/unittests/serialisation/rebuild_models.jl b/test/unittests/serialisation/rebuild_models.jl index 29d1ee99..50b6b18d 100644 --- a/test/unittests/serialisation/rebuild_models.jl +++ b/test/unittests/serialisation/rebuild_models.jl @@ -61,7 +61,7 @@ using Test @test length(d) == 1 @test haskey(d, DiffFusion.alias(usd_model)) d = d[DiffFusion.alias(usd_model)] - for (a, b) in zip(keys(d), ["correlation_holder", "quanto_model", "chi", "sigma_f", "type", "delta", "alias"]) + for (a, b) in zip(keys(d), ["correlation_holder", "quanto_model", "chi", "sigma_f", "scaling_type", "type", "delta", "alias"]) @test a == b end #