commit 1dea6a80e26e3bc9922eba1fcb7bb27173e0e6f2
parent b787aa1236e4cc994c3fcfd077e900d3ca16a101
Author: Erik Loualiche <[email protected]>
Date: Tue, 20 Jan 2026 21:05:56 -0600
Merge pull request #20 from yicheng-wang-fina/bugfix/bond_yield-solver
Bugfix/bond yield solver
Diffstat:
2 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/src/ImportYields.jl b/src/ImportYields.jl
@@ -1547,8 +1547,18 @@ function bond_yield(price, face_value, coupon_rate, years_to_maturity, frequency
return calculated_price - price
end
-
- return Roots.find_zero(price_diff, bracket, Roots.Brent())
+
+ try
+ return Roots.find_zero(price_diff, bracket, Roots.Brent())
+ catch e
+ if isa(e, ArgumentError) && occursin("not a bracketing interval", sprint(showerror, e))
+ # Fall back to a derivative-free method using an initial guess
+ @warn "Brent failed: falling back to Order1" exception=e
+ return Roots.find_zero(price_diff, 0.02, Roots.Order1())
+ else
+ rethrow(e)
+ end
+ end
end
diff --git a/test/UnitTests/Yields.jl b/test/UnitTests/Yields.jl
@@ -311,6 +311,11 @@
@test FinanceRoutines.bond_yield(980, 1000, 0.04, 2.0, 4) > 0.04 # discount bond
# Test annual frequency
@test FinanceRoutines.bond_yield(1020, 1000, 0.03, 5.0, 1) < 0.03 # premium bond
+ # Test case where Brent initially failed due to non-bracketing intervals
+ @test FinanceRoutines.bond_yield_excel(Date("2014-04-24"), Date("2015-12-01"), 0.04, 105.46, 100.0, frequency=2) ≈ 0.0057 atol=5e-4
+ # Two tests with fractional years
+ @test FinanceRoutines.bond_yield_excel(Date("2013-10-08"), Date("2020-09-01"), 0.05, 116.76, 100.0; frequency=2) ≈ 0.0235 atol=5e-4
+ @test FinanceRoutines.bond_yield_excel(Date("2014-07-31"), Date("2032-05-15"), 0.05, 114.083, 100.0; frequency=2) ≈ 0.0389 atol=5e-4
end
end # @testset "GSW Extended Test Suite"
@@ -329,9 +334,3 @@ end # @testset "GSW Extended Test Suite"
-
-
-
-
-
-