Skip to content
Open
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
45 changes: 43 additions & 2 deletions src/DayCounts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -22,7 +22,7 @@ end
abstract type DayCount end

"""
Actual365Fixed()
Actual365Fixed() or Excel.Actual365

**Actual/365 (Fixed)** day count convention.

Expand Down Expand Up @@ -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()

Expand Down
60 changes: 19 additions & 41 deletions src/excel.jl
Original file line number Diff line number Diff line change
@@ -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`.

Expand All @@ -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
Expand All @@ -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
10 changes: 5 additions & 5 deletions test/excel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,39 @@ 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
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
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
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
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
Expand Down
8 changes: 4 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down