1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
import datetime
import pandas as pd
from dateutil.relativedelta import relativedelta, WE
from pandas.tseries.offsets import Day, QuarterBegin
def imm_dates(start_date, end_date):
start_date = bus_day.rollback(start_date) - 19 * Day()
start_date = QuarterBegin(startingMonth=3).rollback(start_date)
# should be close=left I think
return (
pd.date_range(start_date, end_date, freq="QS-MAR", closed=None)
.shift(19, freq="D")
.shift(0, bus_day)
)
def previous_twentieth(d):
r = datetime.date(d.year, d.month, 20)
if r > d:
r -= relativedelta(months=1)
mod = r.month % 3
if mod != 0:
r -= relativedelta(months=mod)
return r
def imm_date(d):
if isinstance(d, str):
d = datetime.date.fromisoformat(d)
r = d + relativedelta(day=1, weekday=WE(3))
if r <= d:
return imm_date(r + relativedelta(months=1, day=1))
return r
def isleapyear(date):
return (date.year % 4) == 0 & (~(date.year % 100 == 0) | date.year % 400 == 0)
def yearfrac(date1, date2, daycount):
if daycount == "30/360":
d1 = date1.dt.day.copy()
d2 = date2.dt.day.copy()
d2[(d2 == 31) & (d1.isin([30, 31]))] = 30
d1.replace({31: 30})
y1 = date1.dt.year
y2 = date2.dt.year
m1 = date1.dt.month
m2 = date2.dt.month
return (360 * (y2 - y1) + 30 * (m2 - m1) + d2 - d1) / 360
days_accrued = date2 - date1
if daycount == "ACT/365":
return days_accrued.dt.days / 365
if daycount == "ACT/360":
return days_accrued.dt.days / 360
|