juliafinance / businessdays.jl Goto Github PK
View Code? Open in Web Editor NEW:calendar: A highly optimized Business Days calculator written in Julia language. Also known as Working Days calculator.
License: Other
:calendar: A highly optimized Business Days calculator written in Julia language. Also known as Working Days calculator.
License: Other
Looks like UKSettlement
points May 4th 2020 as Early May Bank Holiday, but it should be May 8th.
I know that dates may be subtracted, still this seems a natural export for this package. And you can be careful about these distinctions:
using Base.Dates, Base.DateTime
const A_DAY = Day(1)
"""the count of days that are bring
min(a_date, b_date) to max(a_date, b_date)
"""
days_apart(a_date, b_date) = abs(a_date - b_date)
"""the count of days that are between a_date and b_date, excluding a_date and b_date"""
days_inbetween(a_date, b_date) = days_apart(a_date, b_date) - A_DAY
""the number of days that bring a_date into b_date
a_date = b_date + days_apart(a_date, b_date)
b_date = a_date + days_apart(b_date, a_date)
"""
days_separating(a_date, b_date) = (a_date - b_date)
I am trying to use this package with a dataset which has dates starting from 1960. The error that I get is - Date out of cache bounds. Use initcache function with a wider time spread. How do I specify wide time spread in initcache.
2022 UK holidays slightly move due to Platinum Jubilee.
https://inews.co.uk/news/today-bank-holiday-spring-moved-1658202
19/06 is a new national holiday in the US
This code doesn´t work
using BusinessDays, Dates
BusinessDays.advancebdays(:BRSettlement, Date(2018,2,1), 5:-1:1)
Hello @felipenoris, would you mind explaining the rationale when counting the business days between two dates, to not include the end date?
In example below, the start date is a US public holiday and the end date is a working business day and the result for counting business days is zero. Same result if the start date is equal to the end date.
using BusinessDays, Dates
cal = BusinessDays.USSettlement() # US calendar
d1 = Date(2021, 11, 25)
d2 = Date(2021, 11, 26)
bdayscount(cal, d1, d2) # count = 0
bdayscount(cal, d2, d2) # count = 0
Could you also confirm that the workaround to include the end date would be to add one day to d2: bdayscount(cal, d1, d2 + Day(1))
?
It might be worth adding a note on this in the documentation.
Thanks and regards.
Update the docs giving the source for this calendar as SIFMA https://www.sifma.org/resources/general/holiday-schedule/.
The HolidayCalendarCache as implemented is not type stable due to the hc field being of abstract type HolidayCalendar. This then causes unnecessary allocations and is a degrades performance.
I suppose either the HCC struct should be made generic - parametrized on the type of calendar it holds.
@aviks , Date(2011,1,3)
was really not a business day in Canada?
julia> dt = [ Date(2011,1,1), Date(2011,1,2), Date(2011,1,3), Date(2011,1,4) ]
4-element Array{Date,1}:
2011-01-01
2011-01-02
2011-01-03
2011-01-04
julia> using BusinessDays
julia> isbday(:Canada, dt)
4-element Array{Bool,1}:
false
false
false
true
See #48
Hi there,
I have a script that fetches public holidays for Australia from a government website.
The results are stored in a Set{Date}
.
To use the BusinessDays
API (which is great) I construct a calendar using the code below.
I repeat this for every Australian state.
using BusinessDays
struct GenericCalendar
holidays::Set{Date}
end
BusinessDays.isholiday(cal::GenericCalendar, dt::Date) = in(dt, cal.holidays)
cal = GenericCalendar(holidays) # holidays is a set of dates fetched from a govt website
I use the code snippet above quite a lot, and it's generic provided that the dates are specified rather than derived from rules (such as "1st Monday of August").
Would it be possible to include it in BusinessDays
?
Cheers,
Jock
bdays
and bdayscount
sometimes give wrong number of business days as demonstrated for August 2022 and the USSettlement
calendar:
julia> import BusinessDays as bd
julia> using Dates
julia> bd.initcache(bd.USSettlement())
julia> bd.bdays(bd.USSettlement(), Date(2022, 8), Date(2022, 8, 31))
22 days
julia> bd.bdayscount(bd.USSettlement(), Date(2022, 8), Date(2022, 8, 31))
22
julia> bd.listbdays(bd.USSettlement(), Date(2022, 8), Date(2022, 8, 31))
23-element Vector{Date}:
2022-08-01
2022-08-02
2022-08-03
2022-08-04
2022-08-05
2022-08-08
2022-08-09
2022-08-10
2022-08-11
2022-08-12
2022-08-15
2022-08-16
2022-08-17
2022-08-18
2022-08-19
2022-08-22
2022-08-23
2022-08-24
2022-08-25
2022-08-26
2022-08-29
2022-08-30
2022-08-31
julia> length(bd.listbdays(bd.USSettlement(), Date(2022, 8), Date(2022, 8, 31)))
23
I am using julia 1.8.2 on an M1 series iMac:
julia> versioninfo()
Julia Version 1.8.2
Commit 36034abf260 (2022-09-29 15:21 UTC)
Platform Info:
OS: macOS (arm64-apple-darwin21.3.0)
CPU: 8 × Apple M1
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-13.0.1 (ORCJIT, apple-m1)
Threads: 1 on 4 virtual cores
Inspired by the job done at https://github.com/felipenoris/bdays, I'm planning a major breaking change for how cache works in this package.
Planned changes:
BusinessDays.initcache
will be removed
BusinessDays.HolidayCalendarCache
will be a subtype of BusinessDays.HolidayCalendar
Collateral effects:
These changes imply that bdays(:calendar_symbol, d0, d1
method won't work for cached calendars anymore. The user will need to pass an instance of HolidayCalendarCache
.
internal package state variable BusinessDays. CACHE_DICT
will be removed.
After this change, I'll tag a v0.10.0 transition version with deprecation warnings, and then I'll release a v1.0.0, in compliance with Semantic Versioning .
Hi quick question. The tutorial in the documentation states the following about tobday
# Adjust to next business day
julia> tobday(:USSettlement, Date(2015, 1, 1))
2015-01-02
However it appears this is only true if the input date is NOT a business day.
julia> isbday(:USNYSE, Date(2024,03,17))
false
julia> tobday(:USNYSE, Date(2024,03,17))
2024-03-18
If the input date is a business day tobday
does NOT adjust
to the NEXT business day, but rather returns the SAME business day.
julia> isbday(:USNYSE, Date(2024,03,18))
true
julia> tobday(:USNYSE, Date(2024,03,18))
2024-03-18
(One can argue what adjust
means but I think that is asking an ambiguous term to do alot of work in a user manual.)
Should this distinction should be clarified in the documentation because it may lead to confusion and error as the package reaches an even wider audience? Thanks.
they may require custom hash function.
** Forgot that TARGET() calendar also excludes weekends. Closing the issue.
Running the following script
date = Date(2020,12,23)
for i in 1:12
newdate = date + Day(i)
println(newdate, " ", BusinessDays.isbday(TARGET(), newdate))
end
one gets
2020-12-24 true
2020-12-25 false
2020-12-26 false
2020-12-27 false
2020-12-28 true
2020-12-29 true
2020-12-30 true
2020-12-31 true
2021-01-01 false
2021-01-02 false
2021-01-03 false
2021-01-04 true
function isweekend(dt::Date)
return signbit(5 - dayofweek(dt))
end
function isweekday(dt::Date)
return signbit(dayofweek(dt) - 6)
end
These have worked well for me, and may run faster for you.
The only reason not to do this is that other settlement calendars within the EuroZone differ, but that is as with some stock exchanges in a country. Doing this keeps a consistent presentation (:__Settlement, :PlaceName). And probably make :TARGET2 a synonym for :TARGET (for accuracy -- they do not overlap). It is looking good.
I am working with a local module that depends on BusinessDays and get the below message when importing the module.
WARNING: eval into closed module BusinessDays:
:UnitedStates
** incremental compilation may be fatally broken for this module **
My module is just a wrapper around some reporting processes that my firm uses frequently. It is pretty much like this:
module MyModule
using BusinessDays
BusinessDays.initcache(:UnitedStates)
function foo(x, y)
bdays(:UnitedStates, x, y)
end
end # module
Is this a problem with my code?
bdays will be redefined as:
bdays(cal,d0,d1) = Dates.Day(bdayscount(cal,d0,d1))
Since chinese use both lunar and solar calendars, and easy way to support is to use the file from existing project https://github.com/rainx/cn_stock_holidays/blob/master/cn_stock_holidays/data.txt .
I think it would be convenient if you could do date arithmetic. For example, if I want somebody to pass a period to another function, I want to be able to have that period be a day, month, or business day. I think this could be pretty simply done by adding a new type:
struct BDay <: DatePeriod
value::Int64
calendar::Union{Symbol, String}
BDay(v::Number, cal::Union{Symbol, String}) = new(v, cal)
end
Base.:(+)(dt::Date, z::BDay) = advancebdays(z.calendar, dt, z.value)
Base.:(-)(dt::Date, z::BDay) = advancebdays(z.calendar, dt, -1 * z.value)
Which allows for easy calculations:
d1 = today()
c = BDay(1, :USNYSE)
d1 - c
# 2021-09-16
And for writing easy functions:
change_days(dt::Date, c::DatePeriod) = dt + c
change_days(today(), Day(2)) # 2021-09-19
change_days(today(), BDay(2, :USNYSE)) # 2021-09-21
Please add a calendar for the Euro zone "TARGET" / "TARGET2" Closing Days TARGET2
(see also Public_holidays_in_the_European_Union not the same thing, although also useful)
They are closed
yyyy-01-01 New Year's Day
yyyy-mm-dd Good Friday (date varies)
yyyy-mm-dd Easter Monday (date varies)
yyyy-05-01 Labour Day
yyyy-12-25 Christmas Day
yyyy-12-26 Christmas Holiday
YEAR GOOD EASTER
FRIDAY MONDAY
Date Date Date
2001 13-April 16-April
2002 29-April 1-April
2003 18-April 21-April
2004 9-April 12-April
2005 25-April 28-March
2006 14-April 17-April
2007 6-April 9-April
2008 21-March 24-March
2009 10-April 13-April
2010 2-April 5-April
2011 22-April 25-April
2012 6-April 9-April
2013 28-March 1-April
2014 18-April 21-April
2015 3-April 6-April
2016 25-March 28-March
2017 14-April 17-April
2018 30-March 2-April
2019 19-April 22-April
2020 10-April 13-April
2021 2-April 5-April
2022 15-April 18-April
2023 7-April 10-April
2024 29-March 1-April
2025 18-April 21-April
2026 3-April 6-April
2027 26-March 29-March
2028 14-April 17-April
2029 30-March 2-April
2030 19-April 22-April
There have been a number of commits on the issue of Veteran's Day, 2023 ( 69da78a 2b32af3 df48833 ). It falls on Nov 11th 2023, and the code claims it is observed on Nov 10th. That does not reflect the stated data source which says there is no recommended Veteran's day in 2023.
referencing:
these lines
Base.convert{T<:HolidayCalendar}(::Type{Vector{T}}, syms::Vector{Symbol}) = symtocalendar.(syms)
Base.convert{T<:HolidayCalendar, S<:AbstractString}(::Type{Array{T,1}}, strs::Array{S, 1}) = strtocalendar.(strs)
These conversion introduce a bug when creating an empty dictionary:
To reproduce (on julia 0.6):
julia> using BusinessDays
julia> Dict(Any[])
ERROR: UndefRefError: access to undefined reference
Stacktrace:
[1] collect(::Base.Generator{UnitRange{Int64},Base.Broadcast.##1#2{Tuple{Array{Union{},1}},Tuple{Tuple{Bool}},Tuple{Tuple{Int64}},CartesianIndex{1}}}) at ./array.jl:441
[2] broadcast_t(::Function, ::Type{Any}, ::Tuple{Base.OneTo{Int64}}, ::CartesianRange{CartesianIndex{1}}, ::Array{Union{},1}) at ./broadcast.jl:256
[3] broadcast_c at ./broadcast.jl:319 [inlined]
[4] broadcast at ./broadcast.jl:434 [inlined]
[5] convert(::Type{Array{Union{},1}}, ::Array{Union{},1}) at /home/muchmore/.julia/v0.6/BusinessDays/src/holidaycalendar.jl:27
[6] grow_to!(::Dict{Any,Any}, ::Array{Any,1}) at ./dict.jl:173
[7] Dict(::Array{Any,1}) at ./dict.jl:145
This seems to be an issue related to the type system changes introduced in v0.6 -- I do not get this error in Julia 0.5.
The type matching problem might be fixable, however... a simpler fix would be to just remove them since I don't think they are necessary.
To test it out I removed those two convert methods and everything seems to work just fine (in 0.5 and 0.6)
julia> using BusinessDays
julia> Dict(Any[])
Dict{Any,Any} with 0 entries
julia> convert(Vector{BusinessDays.HolidayCalendar}, ["USNYSE", "USGovernmentBond"])
2-element Array{BusinessDays.HolidayCalendar,1}:
BusinessDays.USNYSE()
BusinessDays.USGovernmentBond()
julia> BusinessDays.HolidayCalendar["USNYSE", "USGovernmentBond"]
2-element Array{BusinessDays.HolidayCalendar,1}:
BusinessDays.USNYSE()
BusinessDays.USGovernmentBond()
julia> BusinessDays.HolidayCalendar[:USNYSE, :USGovernmentBond]
2-element Array{BusinessDays.HolidayCalendar,1}:
BusinessDays.USNYSE()
BusinessDays.USGovernmentBond()
The tests seem to be going into an infinite loop. I discovered this trying to troubleshoot JuliaLang/julia#18276
Reporting here in case it is an issue with this package for 0.5. If it is a julia problem, would be good to know.
When using the package, I got error LoadError: UndefVarError: Friday not defined
One example would be,
src/calendars/brazil.jl (line 88), which use the variable Friday
while it should be Dates.Friday
There maybe similar use of variables that's not exported by Base
same goes for us.jl around line 158, dayofyear
A simple test would be call listholidays
for each calendar over the past hundred years and the next hundred years or so (say 1900-01-01 to 2100-01-01) and it pretty much catch these corner cases
Many financial uses of your package will involve a collection of calendars, one for each country with an exchange of interest. It seems to me that you could bring the throughput that you have with the current distinguished calendar to each of the (really not very many) calendars offered. A simple way, just to convey the idea, would be to use a dictionary that takes as keys hash(calendar)
and the values are the respective cache realizations. Your implementation is sound ..
Is there an easy way to create a new GenericHolidayCalendar
struct - where the weekends are considered business days, unless they are in the holidays
field of the GenericHolidayCalendar
- other than dublicate the entire GenericHolidayCalendar
struct in
https://github.com/JuliaFinance/BusinessDays.jl/blob/master/src/generic.jl and change the isbday
function?
Executing BusinessDays.initcache(:Brazil)
results in a noisy output:
BusinessDays.HolidayCalendarCache(BusinessDays.BRSettlement(),Bool[false,true,true,true,false,false,true,true,true,true … true,false,false,true,true,true,true,true,false,false],UInt32[0x00000000,0x00000001,0x00000002,0x00000003,0x00000003,0x00000003,0x00000004,0x00000005,0x00000006,0x00000007 … 0x0000a7bf,0x0000a7bf,0x0000a7bf,0x0000a7c0,0x0000a7c1,0x0000a7c2,0x0000a7c3,0x0000a7c4,0x0000a7c4,0x0000a7c4],1980-01-01,2150-12-20)
It should be supressed or improved to avoid slowdown.
Hi @felipenoris
I was looking to add some additional calendars to this package, but looking at the existing code, I had a question. Why does the code in the isHoliday
function contains a bisection. In other words, why does it have a if m>=8 ... else ...
construct? Is there a performance reason? Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.