(* :Title: Calendar functions *) (* :Context: QuantLib`Calendar` *) (* :Author: Niels Elken Sønderby *) (* :Mathematica Version: 4.0 *) (* :Copyright: Copyright (C) 2003 Niels Elken Sønderby *) (* :License: This file is part of QuantLib for Mathematica, a Mathematica extension for QuantLib, a free-software/open-source financial C++ library - http://www.nielses.dk/quantlib/mma/ - http://quantlib.org/ QuantLib for Mathematica is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email ferdinando@ametrano.net The license is also available online at http://quantlib.org/html/license.html This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. *) BeginPackage["QuantLib`Calendar`", "QuantLib`Common`QuantLibCommon`" (* Needs SymbolToNumber functionality *) ] (* Usage messages *) DayOfWeek::usage = "DayOfWeek[{y, m, d}] gives the day of the week for year y, month m, and day d." $DaysOfWeek::usage = "$DaysOfWeek contains a list of the days of the week." Sunday::usage = "Sunday is a day of the week." Monday::usage = "Monday is a day of the week." Tuesday::usage = "Tuesday is a day of the week." Wednesday::usage = "Wednesday is a day of the week." Thursday::usage = "Thursday is a day of the week." Friday::usage = "Friday is a day of the week." Saturday::usage = "Saturday is a day of the week." BusinessDayQ::usage = "BusinessDayQ[{y, m, d}, HolidayCalendar -> calendar] returns True if the date is a business day in the given calendar." HolidayQ::usage = "HolidayQ[{y, m, d}, HolidayCalendar -> calendar] returns True if the date is a holiday in the given calendar." HolidayCalendar::usage = "HolidayCalendar is an option for several date functions specifying the dates that are not business days, examples are TokyoCalendar and MilanCalendar." $HolidayCalendars::usage = "$HolidayCalendars is a list of available holiday calendars." FrankfurtCalendar::usage = "FrankfurtCalendar is a holiday calendar representing the Frankfurt calendar." HelsinkiCalendar::usage = "HelsinkiCalendar is a holiday calendar representing the Helsinki calendar." JohannesburgCalendar::usage = "JohannesburgCalendar is a holiday calendar representing the Johannesburg calendar." LondonCalendar::usage = "LondonCalendar is a holiday calendar representing the London calendar." MilanCalendar::usage = "MilanCalendar is a holiday calendar representing the Milan calendar." NewYorkCalendar::usage = "NewYorkCalendar is a holiday calendar representing the New York calendar." SydneyCalendar::usage = "SydneyCalendar is a holiday calendar representing the Sydney (New South Wales, Australia) calendar." TARGETCalendar::usage = "TARGETCalendar is a holiday calendar representing the Trans-European Automated Real-time Gross Express-settlement Transfer system calendar. http://www.ecb.int/press/00/pr001214_4.htm" TokyoCalendar::usage = "TokyoCalendar is a holiday calendar representing the Tokyo calendar." TorontoCalendar::usage = "TorontoCalendar is a holiday calendar representing the Toronto calendar." WellingtonCalendar::usage = "WellingtonCalendar is a holiday calendar representing the Wellington calendar." ZurichCalendar::usage = "ZurichCalendar is a holiday calendar representing the Zurich calendar." DaysPlus::usage = "DaysPlus[{y, m, d}, days, HolidayCalendar -> calendar] advances the given date with the given number of business days." RollDate::usage = "RollDate[{y, m, d}, HolidayCalendar -> calendar, RollingConvention -> roll]" $RollingConventions::usage = "$RollingsConventions contains a list of available rolling conventions." RollingConvention::usage = "RollingConvention is an option for date functions which specifies how dates are adjusted if they fall on a holiday." Preceding::usage = "Preceding is a rolling convention, which adjust to the first business day before the given holiday." ModifiedPreceding::usage = "ModifiedPreceding is a rolling convention, which adjusts to the first business day before the given holiday unless it belongs to a different month, in which case it adjusts to the first business day after the holiday." Following::usage = "Following is a rolling convention, which adjust to the first business day after the given holiday." ModifiedFollowing::usage = "ModifiedFollowing is a rolling convention, which adjusts to the first business day after the given holiday unless it belongs to a different month, in which case it adjusts to the first business day before the holiday." Actual365::usage = "Actual365 represents the Actual/365 day counting convention." Actual360::usage = "Actual360 represents the Actual/360 day counting convention." Thirty360American::usage = "Thirty360American represents the American (NASD) variant of the 30/360 day counting convention: if the starting date is the 31st of a month, it becomes equal to the 30th of the same month. If the ending date is the 31st of a month and the starting date is earlier than the 30th of a month, the ending date becomes equal to the 1st of the next month, otherwise the ending date becomes equal to the 30th of the same month." Thirty360European::usage = "Thirty360European represents the European variant of the 30/360 day counting convention: starting dates or ending dates that occur on the 31st of a month become equal to the 30th of the same month." Thirty360Italian::usage = "Thirty360Italian represents the Italian variant of the 30/360 day counting convention: starting dates or ending dates that occur on February and are greater than 27 become equal to 30 for computational sake." ActualActualISMA::usage = "ActualActualISMA represents the ISMA Actual/Actual day counting convention. Also known as Actual/Actual Bond." ActualActualAFB::usage = "ActualActualAFB represents the AFB Actual/Actual day counting convention. Also known as Actual/Actual Euro." ActualActualISDA::usage = "ActualActualISDA represents the ISDA Actual/Actual day counting convention. Also known as Actual/Actual Historical." DayCountConvention::usage = "DayCountConvention is an option for date functions that specifies the length of months and other rules." $DayCountConventions::usage = "$DayCountConventions contains a list of available day count conventions." DaysBetween::usage = "DaysBetween[{y1_,m1_,d1_},{y2_,m2_,d2}, DayCountConvention-> daycount] gives the number of days from the first date to the second using the given day count convention." YearsBetween::usage = "YearsBetween[{y1_,m1_,d1_},{y2_,m2_,d2}, DayCountConvention-> daycount] gives the fraction of years between the two dates using the given day count convention." LeapYearQ::usage = "LeapYearQ[{y, m, d}] or LeapYearQ[year] returns true if the date is in a leap year." Begin["`Private`"] (* Give access to QuantLib`Private` context as LinkPatterns for external program are there. Does a more elegant solution exist? *) AppendTo[$ContextPath, "QuantLib`Private`"] (* Translation table for passing "enum"-values to C++ *) DayOfWeekNumbers = { {Sunday, 1}, {Monday, 2}, {Tuesday, 3}, {Wednesday, 4}, {Thursday, 5}, {Friday, 6}, {Saturday, 7} } $DaysOfWeek = Transpose[DayOfWeekNumbers][[1]] DayOfWeek[{y_,m_,d_}] := NumberToSymbol[qlDayOfWeek[y,m,d],DayOfWeekNumbers] $HolidayCalendar = TARGETCalendar; (* Default value *) (* Translation table for passing "enum"-values to C++ *) HolidayCalendarNumbers = { { FrankfurtCalendar, 2 }, { HelsinkiCalendar, 3 }, { JohannesburgCalendar, 4 }, { LondonCalendar, 5 }, { MilanCalendar, 6 }, { NewYorkCalendar, 7 }, { SydneyCalendar, 10 }, { TARGETCalendar, 11 }, { TokyoCalendar, 12 }, { TorontoCalendar, 13 }, { WellingtonCalendar, 15 }, { ZurichCalendar, 16 } } $HolidayCalendars = Transpose[HolidayCalendarNumbers][[1]] BusinessDayQ[{y_, m_, d_}, opts___?OptionQ] := Module[{holidaycal}, holidaycal = HolidayCalendar /. {opts} /. Options[BusinessDayQ]; If[holidaycal === None, True, (* To be consistent with ShiftDate *) (* DayOfWeek[{y, m, d}] =!= Saturday =!= Sunday, *) qlBusinessDayQ[y,m,d, SymbolToNumber[holidaycal, HolidayCalendarNumbers]]] ] BusinessDayQ[lst : {{_, _, _} ..}, opts___?OptionQ] := BusinessDayQ[#, opts]& /@ lst Options[BusinessDayQ] := { HolidayCalendar -> $HolidayCalendar } HolidayQ[lst : {{_, _, _} ..}, opts___?OptionQ] := (!BusinessDayQ[#, opts])& /@ lst HolidayQ[args_, opts___?OptionQ] := !BusinessDayQ[args, opts] DaysPlus[{y_, m_, d_}, days_, opts___?OptionQ] := Module[{holidaycal, calnum}, holidaycal = HolidayCalendar /. {opts} /. Options[DaysPlus]; If[holidaycal === None, calnum=0, calnum=SymbolToNumber[holidaycal, HolidayCalendarNumbers]]; qlShiftDate[y,m,d,0,0,days,calnum] ] Options[DaysPlus] := { HolidayCalendar -> None } $RollingConvention = Following; (* Default value *) (* Translation table for passing "enum"-values to C++ *) RollingConventionNumbers = { { Preceding, 1 }, { ModifiedPreceding, 2 }, { Following, 3 }, { ModifiedFollowing, 4 } } $RollingConventions = Transpose[RollingConventionNumbers][[1]] RollDate[{y_, m_, d_}, opts___?OptionQ] := Module[{holidaycal, rollconv, calnum, rollnum}, holidaycal = HolidayCalendar /. {opts} /. Options[RollDate]; rollconv = RollingConvention /. {opts} /. Options[RollDate]; calnum = SymbolToNumber[holidaycal, HolidayCalendarNumbers]; rollnum = SymbolToNumber[rollconv, RollingConventionNumbers]; qlRollDate[y, m, d, calnum, rollnum] ] Options[RollDate] := { HolidayCalendar -> $HolidayCalendar, RollingConvention -> $RollingConvention } $DayCountConvention = Actual365; (* Default value *) (* Translation table for passing "enum"-values to C++ *) DayCountConventionNumbers = { { Actual365, 1 }, { Actual360, 2 }, { Thirty360American, 3 }, { Thirty360European, 4 }, { Thirty360Italian, 5 }, { ActualActualISMA, 6 }, { ActualActualAFB, 7 }, { ActualActualISDA, 8 } } $DayCountConventions = Transpose[DayCountConventionNumbers][[1]] DaysBetween[{y1_,m1_,d1_},{y2_,m2_,d2_}, opts___?OptionQ] := Module[{daycount, daycountnum}, daycount = DayCountConvention /. {opts} /. Options[DaysBetween]; daycountnum = SymbolToNumber[daycount, DayCountConventionNumbers]; qlDaysBetween[y1,m1,d1,y2,m2,d2,daycountnum] ] Options[DaysBetween] := { DayCountConvention -> $DayCountConvention } (* Reference period only needed for ActualActualISMA *) YearsBetween[{y1_, m1_, d1_}, {y2_, m2_, d2_}, {refy1_, refm1_, refd1_}, {refy2_, refm2_, refd2_}, opts___?OptionQ] := Module[{daycount, daycountnum}, daycount = DayCountConvention /. {opts} /. Options[DaysBetween]; daycountnum = SymbolToNumber[daycount, DayCountConventionNumbers]; qlYearsBetween[y1, m1, d1, y2, m2, d2, refy1, refm1, refd1, refy2, refm2, refd2, daycountnum] ] YearsBetween[{y1_, m1_, d1_}, {y2_, m2_, d2_}, opts___?OptionQ] := YearsBetween[{y1,m1,d1}, {y2,m2,d2}, {0,0,0}, {0,0,0}, opts] Options[YearsBetween] := { DayCountConvention -> $DayCountConvention } LeapYearQ[y_Integer]:=qlLeapYearQ[y] Attributes[LeapYearQ] := {Listable} End[] EndPackage[]