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