diff --git a/src/DayCounts.jl b/src/DayCounts.jl index 649b57e..4195bb4 100644 --- a/src/DayCounts.jl +++ b/src/DayCounts.jl @@ -4,7 +4,7 @@ module DayCounts # https://www.isda.org/2008/12/22/30-360-day-count-conventions/ using Dates -export yearfrac +export yearfrac, Excel """ yearfrac(startdate::Date, enddate::Date, dc::DayCount) @@ -22,7 +22,7 @@ end abstract type DayCount end """ - Actual365Fixed() + Actual365Fixed() or Excel.Actual365 **Actual/365 (Fixed)** day count convention. @@ -194,6 +194,47 @@ function yearfrac(startdate::Date, enddate::Date, dc::Thirty360) return thirty360(dy,dm,d2-d1) end +""" + ThirtyU360() or Excel.Thirty360 + +**US (NASD) 30/360** day count convention, as computed via Microsoft Excel `YEARFRAC` with the basis option of `0`. + +This differs from [`Thirty360`](@ref) when: +* if the start date is the last day of February, then + - ``d_1`` is 30, and + - if the end date is also the last day of February ``d_2`` is also 30. + +# Reference +- [Microsoft Excel `YEARFRAC` function](https://support.office.com/en-us/article/yearfrac-function-3844141e-c76d-4143-82b6-208454ddc6a8) +- [David A. Wheeler (2008) "YEARFRAC Incompatibilities between Excel 2007 and OOXML (OXML), and the Definitions Actually Used by Excel 2007"](https://dwheeler.com/yearfrac/excel-ooxml-yearfrac.pdf) +""" +struct ThirtyU360 <: DayCount end +function yearfrac(startdate::Date, enddate::Date, dc::ThirtyU360) + if startdate > enddate + return -yearfrac(enddate, startdate, dc) + end + + y1 = year(startdate) + y2 = year(enddate) + m1 = month(startdate) + m2 = month(enddate) + d1 = day(startdate) + d2 = day(enddate) + if d1 >= 30 + d1 = 30 + if d2 >= 30 + d2 = 30 + end + elseif m1 == 2 && startdate == lastdayofmonth(startdate) + d1 = 30 + if m2 == 2 && enddate == lastdayofmonth(enddate) + d2 = 30 + end + end + return DayCounts.thirty360(y2-y1,m2-m1,d2-d1) +end +yearfrac(startdate::Date, enddate::Date) = DayCounts.yearfrac(startdate::Date, enddate::Date, ThirtyU360()) # Defaul DayCount + """ ThirtyE360() diff --git a/src/excel.jl b/src/excel.jl index 56b3428..e55a627 100644 --- a/src/excel.jl +++ b/src/excel.jl @@ -1,46 +1,14 @@ -""" - Thirty360Excel() +module Excel -**US (NASD) 30/360** day count convention, as computed via Microsoft Excel `YEARFRAC` with the basis option of `0`. +using ..DayCounts, ..Dates -This differs from [`Thirty360`](@ref) when: -* if the start date is the last day of February, then - - ``d_1`` is 30, and - - if the end date is also the last day of February ``d_2`` is also 30. +@doc (@doc DayCounts.ThirtyU360) +const Thirty360 = DayCounts.ThirtyU360 -# Reference -- [Microsoft Excel `YEARFRAC` function](https://support.office.com/en-us/article/yearfrac-function-3844141e-c76d-4143-82b6-208454ddc6a8) -- [David A. Wheeler (2008) "YEARFRAC Incompatibilities between Excel 2007 and OOXML (OXML), and the Definitions Actually Used by Excel 2007"](https://dwheeler.com/yearfrac/excel-ooxml-yearfrac.pdf) """ -struct Thirty360Excel <: DayCount -end -function yearfrac(startdate::Date, enddate::Date, dc::Thirty360Excel) - if startdate > enddate - return -yearfrac(enddate, startdate, dc) - end - - y1 = year(startdate) - y2 = year(enddate) - m1 = month(startdate) - m2 = month(enddate) - d1 = day(startdate) - d2 = day(enddate) - if d1 >= 30 - d1 = 30 - if d2 >= 30 - d2 = 30 - end - elseif m1 == 2 && startdate == lastdayofmonth(startdate) - d1 = 30 - if m2 == 2 && enddate == lastdayofmonth(enddate) - d2 = 30 - end - end - return thirty360(y2-y1,m2-m1,d2-d1) -end + Excel.ActualActual() -""" - ActualActualExcel() +Excel Basis = 1 **Actual/Actual** day count convention, as computed via Microsoft Excel `YEARFRAC` with the basis option of `1`. @@ -59,9 +27,8 @@ where: - [Microsoft Excel `YEARFRAC` function](https://support.office.com/en-us/article/yearfrac-function-3844141e-c76d-4143-82b6-208454ddc6a8) - [David A. Wheeler (2008) "YEARFRAC Incompatibilities between Excel 2007 and OOXML (OXML), and the Definitions Actually Used by Excel 2007"](https://dwheeler.com/yearfrac/excel-ooxml-yearfrac.pdf) """ -struct ActualActualExcel <: DayCount -end -function yearfrac(startdate::Date, enddate::Date, dc::ActualActualExcel) +struct ActualActual <: DayCounts.DayCount end +function DayCounts.yearfrac(startdate::Date, enddate::Date, dc::ActualActual) if startdate > enddate return -yearfrac(enddate, startdate, dc) end @@ -81,3 +48,14 @@ function yearfrac(startdate::Date, enddate::Date, dc::ActualActualExcel) return Dates.value(enddate-startdate) / (sum(daysinyear, yrange) / length(yrange)) end end + +@doc (@doc DayCounts.Actual360) +const Actual360 = DayCounts.Actual360 + +@doc (@doc DayCounts.Actual365Fixed) +const Actual365 = DayCounts.Actual365Fixed + +@doc (@doc DayCounts.ThirtyE360) +const ThirtyE360 = DayCounts.ThirtyE360 + +end \ No newline at end of file diff --git a/test/excel.jl b/test/excel.jl index 1223654..1883c18 100644 --- a/test/excel.jl +++ b/test/excel.jl @@ -2,7 +2,7 @@ using Test, DayCounts, Dates, ExcelFiles @testset "Excel basis 0" begin table = load("yearfrac.xlsx","basis0") - dc = DayCounts.Thirty360Excel() + dc = DayCounts.Excel.Thirty360() for r in ExcelFiles.getiterator(table) @test yearfrac(Date(r.startdate), Date(r.enddate), dc) == r.yearfrac end @@ -10,7 +10,7 @@ end @testset "Excel basis 1" begin table = load("yearfrac.xlsx","basis1") - dc = DayCounts.ActualActualExcel() + dc = DayCounts.Excel.ActualActual() for r in ExcelFiles.getiterator(table) @test yearfrac(Date(r.startdate), Date(r.enddate), dc) == r.yearfrac end @@ -18,7 +18,7 @@ end @testset "Excel basis 2" begin table = load("yearfrac.xlsx","basis2") - dc = DayCounts.Actual360() + dc = DayCounts.Excel.Actual360() for r in ExcelFiles.getiterator(table) @test yearfrac(Date(r.startdate), Date(r.enddate), dc) == r.yearfrac end @@ -26,7 +26,7 @@ end @testset "Excel basis 3" begin table = load("yearfrac.xlsx","basis3") - dc = DayCounts.Actual365Fixed() + dc = DayCounts.Excel.Actual365() for r in ExcelFiles.getiterator(table) @test yearfrac(Date(r.startdate), Date(r.enddate), dc) == r.yearfrac end @@ -34,7 +34,7 @@ end @testset "Excel basis 4" begin table = load("yearfrac.xlsx","basis4") - dc = DayCounts.ThirtyE360() + dc = DayCounts.Excel.ThirtyE360() for r in ExcelFiles.getiterator(table) @test yearfrac(Date(r.startdate), Date(r.enddate), dc) == r.yearfrac end diff --git a/test/runtests.jl b/test/runtests.jl index 578f9a3..9c62309 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -289,8 +289,8 @@ end end -@testset "Thirty360Excel" begin - dc = DayCounts.Thirty360Excel() +@testset "ThirtyU360" begin + dc = DayCounts.ThirtyU360() # usual rule: ((d2-d1) + (m2-m1)*30 + (y2-y1)*360)/360 @test yearfrac(Date(2011,12,28), Date(2012, 2,28), dc) == ((28-28) + (2-12)*30 + (2012-2011)*360)/360 @test yearfrac(Date(2011,12,28), Date(2012, 2,29), dc) == ((29-28) + (2-12)*30 + (2012-2011)*360)/360 @@ -325,8 +325,8 @@ end -@testset "ActualActualExcel" begin - dc = DayCounts.ActualActualExcel() +@testset "Excel.ActualActual" begin + dc = DayCounts.Excel.ActualActual() # calculated from Excel sheet @test yearfrac(Date(2011,12,28), Date(2012, 2,28), dc) == 62/365 @test yearfrac(Date(2011,12,28), Date(2012, 2,29), dc) == 63/366