Giter Site home page Giter Site logo

juliafinance / businessdays.jl Goto Github PK

View Code? Open in Web Editor NEW
63.0 5.0 21.0 802 KB

:calendar: A highly optimized Business Days calculator written in Julia language. Also known as Working Days calculator.

License: Other

Julia 99.30% R 0.70%
calendar holidays bank-holidays quantlib julia-language easter valuation days-calculator

businessdays.jl's People

Contributors

aviks avatar felipenoris avatar femtotrader avatar getzdan avatar jmkuhn avatar jocklawrie avatar kcajf avatar lucasprocessi avatar pb866 avatar technophobiclampshade avatar thedacheng avatar tkelman avatar waldyrious avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

businessdays.jl's Issues

easy-peasy days(date,date) like bdays

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) 

Error in using BusinessDays

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.

Include end date in calculation

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.

HolidayCalendarCache is not type stable

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.

Checking Canada holidays

@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

Request: New type for generic calendar

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 bdays count give wrong number of business days

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

[Breaking] changes for HolidayCalendarCache

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 .

Documentation Clarification/Error in Tutorial.

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.

Issue with TARGET calendar

** 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

maybe make :EuroZone a synonym for :TARGET

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.

eval into closed module BusinessDays

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?

Add type to easily add or substract business days

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

Add Euro Zone calendar

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

Bug with conversion functions on julia 0.6

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()

Friday not defined

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

why cache only one calendar?

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 ..

Supress or improve show method for HolidayCalendarCache

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.

Why does the isHoliday method have a bisection

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!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.