def get_tiaocang_date(start_date, end_date, freq=FreqType.EOM, calendar='China.SSE', date_format='%Y-%m-%d'): """ :param start_date: str/datetime.datetime, 开始日期 :param end_date: str/datetime.datetime, 结束日期 :param freq: str enum, default=EOM, 月度 :param calendar: str, 日历名称 :param date_format: str, start_date/end_date 如果是str格式,其格式的日期形式 :return: list, datetime.datetime 返回在开始日至结束日之间的调仓日(交易日) """ calendar = calendar date_format = date_format start_date = ensure_pyfin_date(start_date, date_format) end_date = ensure_pyfin_date(end_date, date_format) cal = Calendar(calendar) tiaocang_date = Schedule(start_date, end_date, Period('1' + freq), cal, BizDayConventions.Unadjusted) if freq.upper() == FreqType.EOW: tiaocang_date = [Date.nextWeekday(date, Weekdays.Friday) for date in tiaocang_date] elif freq.upper() == FreqType.EOM: tiaocang_date = [cal.endOfMonth(date) for date in tiaocang_date] elif freq.upper() == FreqType.EOY: tiaocang_date = [Date(date.year(), 12, 31) for date in tiaocang_date] tiaocang_date = [cal.adjustDate(date, BizDayConventions.Preceding).toDateTime() for date in tiaocang_date if start_date <= date <= end_date] return sorted(set(tiaocang_date))
def testDailySchedule(self): # Jan 2 and Jan 3 are skipped as New Year holiday # Jan 7 is skipped as weekend # Jan 8 is adjusted to Jan 9 with following convention start_date = Date(2012, 1, 1) s = Schedule(start_date, start_date + 7, Period(length=1, units=TimeUnits.Days), Calendar("China.SSE"), BizDayConventions.Preceding) expected = [ Date(2011, 12, 30), Date(2012, 1, 4), Date(2012, 1, 5), Date(2012, 1, 6), Date(2012, 1, 9) ] self.checkDates(s, expected) # The schedule should skip Saturday 21st and Sunday 22rd. # Previously, it would adjust them to Friday 20th, resulting # in three copies of the same date. start_date = Date(2012, 1, 17) s = Schedule(start_date, start_date + 7, Period(length=1, units=TimeUnits.Days), Calendar('Target'), BizDayConventions.Preceding) expected = [ Date(2012, 1, 17), Date(2012, 1, 18), Date(2012, 1, 19), Date(2012, 1, 20), Date(2012, 1, 23), Date(2012, 1, 24) ] self.checkDates(s, expected)
def testCalendarConstructionIsInsensitiveOfCase(self): cal1 = Calendar('NullCalendar') cal2 = Calendar('nullcalendar') shouldBeTrue = cal1 == cal2 self.assertTrue(shouldBeTrue) caltoBeDifferent = Calendar('China.SSE') shouldBeFalse = cal1 == caltoBeDifferent self.assertFalse(shouldBeFalse)
def testChinaIB(self): # China Inter Bank working weekend list in the year 2014 expected_working_week_end = [ Date(2014, 1, 26), Date(2014, 2, 8), Date(2014, 5, 4), Date(2014, 9, 28), Date(2014, 10, 11), # China Inter Bank working weekend list in the year 2015 Date(2015, 1, 4), Date(2015, 2, 15), Date(2015, 2, 28), Date(2015, 9, 6), Date(2015, 10, 10), # China Inter Bank working weekend list in the year 2016 Date(2016, 2, 6), Date(2016, 2, 14), Date(2016, 6, 12), Date(2016, 9, 18), Date(2016, 10, 8), Date(2016, 10, 9), # China Inter Bank working weekend list in the year 2017 Date(2017, 1, 22), Date(2017, 2, 4), Date(2017, 4, 1), Date(2017, 5, 27), Date(2017, 9, 30), # China Inter Bank working weekend list in the year 2018 Date(2018, 2, 11), Date(2018, 2, 24), Date(2018, 4, 8), Date(2018, 4, 28), Date(2018, 9, 29), Date(2018, 9, 30) ] cal = Calendar('China.IB') for day in expected_working_week_end: self.assertEqual( cal.isHoliday(day), False, "{0} is not expected to be a holiday in {1}".format(day, cal)) self.assertEqual( cal.isBizDay(day), True, "{0} is expected to be a working day in {1} ".format(day, cal))
def testCalendarWithDayConvention(self): sse_cal = Calendar('China.SSE') reference_date = Date(2015, 2, 14) test_date = sse_cal.adjustDate( reference_date, BizDayConventions.HalfMonthModifiedFollowing) self.assertEqual(test_date, Date(2015, 2, 13)) reference_date = Date(2014, 2, 4) test_date = sse_cal.adjustDate(reference_date, BizDayConventions.ModifiedPreceding) self.assertEqual(test_date, Date(2014, 2, 7)) reference_date = Date(2014, 2, 3) test_date = sse_cal.adjustDate(reference_date, BizDayConventions.Nearest) self.assertEqual(test_date, Date(2014, 2, 7)) reference_date = Date(2014, 2, 2) test_date = sse_cal.adjustDate(reference_date, BizDayConventions.Nearest) self.assertEqual(test_date, Date(2014, 1, 30)) with self.assertRaises(ValueError): _ = sse_cal.adjustDate(reference_date, -1)
def testScheduleInitializeWithYearly(self): start_date = Date(2012, 2, 29) end_date = Date(2013, 3, 1) tenor = Period('1y') cal = Calendar('NullCalendar') sch = Schedule(start_date, end_date, tenor, cal) expected = [Date(2012, 2, 29), Date(2013, 2, 28), Date(2013, 3, 1)] for i in range(sch.size()): self.assertEqual(expected[i], sch[i])
def testScheduleDeepCopy(self): start_date = Date(2013, 3, 31) end_date = Date(2013, 6, 30) tenor = Period('1m') cal = Calendar('NullCalendar') sch = Schedule(start_date, end_date, tenor, cal) copied_sch = copy.deepcopy(sch) self.assertEqual(sch, copied_sch)
def testNullCalendar(self): cal = Calendar("Null") testDate = Date(2015, 1, 1) self.assertTrue(cal.isBizDay(testDate)) self.assertTrue(not cal.isHoliday(testDate)) self.assertTrue(cal.isWeekEnd(Weekdays.Saturday)) self.assertTrue(cal.isWeekEnd(Weekdays.Sunday)) self.assertTrue(not cal.isWeekEnd(Weekdays.Friday))
def testCalendarPickle(self): sseCal = Calendar('China.SSE') f = tempfile.NamedTemporaryFile('w+b', delete=False) pickle.dump(sseCal, f) f.close() with open(f.name, 'rb') as f2: pickledCal = pickle.load(f2) self.assertEqual(sseCal, pickledCal) os.unlink(f.name)
def get_tiaocang_date(start_date, end_date, freq=FreqType.EOM, calendar='China.SSE', date_format='%Y-%m-%d'): """ :param start_date: str/datetime.datetime, 开始日期 :param end_date: str/datetime.datetime, 结束日期 :param freq: str enum, default=EOM, 月度 :param calendar: str, 日历名称 :param date_format: str, start_date/end_date 如果是str格式,其格式的日期形式 :return: list, datetime.datetime 返回在开始日至结束日之间的调仓日(交易日) """ calendar = calendar date_format = date_format start_date = ensure_pyfin_date(start_date, date_format) end_date = ensure_pyfin_date(end_date, date_format) cal = Calendar(calendar) tiaocang_date = Schedule(start_date, end_date, Period('1' + freq), cal, BizDayConventions.Unadjusted) if freq.upper() == FreqType.EOW: tiaocang_date = [ Date.nextWeekday(date, Weekdays.Friday) for date in tiaocang_date ] elif freq.upper() == FreqType.EOM: tiaocang_date = [cal.endOfMonth(date) for date in tiaocang_date] elif freq.upper() == FreqType.EOY: tiaocang_date = [Date(date.year(), 12, 31) for date in tiaocang_date] tiaocang_date = [ cal.adjustDate(date, BizDayConventions.Preceding).toDateTime() for date in tiaocang_date if start_date <= date <= end_date ] return sorted(set(tiaocang_date))
def testScheduleInitialize(self): start_date = Date(2013, 3, 31) end_date = Date(2013, 6, 30) tenor = Period('1m') cal = Calendar('NullCalendar') sch = Schedule(start_date, end_date, tenor, cal) expected = [ Date(2013, 3, 31), Date(2013, 4, 30), Date(2013, 5, 31), Date(2013, 6, 30) ] for i in range(sch.size()): self.assertEqual(expected[i], sch[i])
def testAdjustDate(self): # April 30, 2005 is a working day under IB, but a holiday under SSE referenceDate = Date(2005, Months.April, 30) sseCal = Calendar('China.SSE') ibCal = Calendar('China.IB') bizDayConv = BizDayConventions.Unadjusted self.assertEqual(sseCal.adjustDate(referenceDate, bizDayConv), referenceDate) self.assertEqual(ibCal.adjustDate(referenceDate, bizDayConv), referenceDate) bizDayConv = BizDayConventions.Following self.assertEqual(sseCal.adjustDate(referenceDate, bizDayConv), Date(2005, Months.May, 9)) self.assertEqual(ibCal.adjustDate(referenceDate, bizDayConv), Date(2005, Months.April, 30)) bizDayConv = BizDayConventions.ModifiedFollowing self.assertEqual(sseCal.adjustDate(referenceDate, bizDayConv), Date(2005, Months.April, 29)) self.assertEqual(ibCal.adjustDate(referenceDate, bizDayConv), Date(2005, Months.April, 30))
def testSchedulePickle(self): start_date = Date(2013, 3, 31) end_date = Date(2013, 6, 30) tenor = Period('1m') cal = Calendar('NullCalendar') sch = Schedule(start_date, end_date, tenor, cal) f = tempfile.NamedTemporaryFile('w+b', delete=False) pickle.dump(sch, f) f.close() with open(f.name, 'rb') as f2: pickled_sch = pickle.load(f2) self.assertEqual(sch, pickled_sch) os.unlink(f.name)
def map_to_biz_day(date_series, calendar='China.SSE', convention=BizDayConventions.Preceding): """ :param date_series: array-like of datetime.datetime :param calendar: str, optional, 日历名称,见PyFin.DateUtilities.Calendar, default='China.SSE' :param convention: str, optional, 如果日期为节假日,如何调整成交易日,见PyFin.DateUtilities.Schedule, default = preceding :return: pd.Series, datetime.datetime, 交易日列表 """ unique_date_list = sorted(set(date_series)) py_date_list = [Date.fromDateTime(date) for date in unique_date_list] py_date_list = [ Calendar(calendar).adjustDate(date, convention) for date in py_date_list ] biz_day_list = [Date.toDateTime(date) for date in py_date_list] dict_date_map = dict(zip(unique_date_list, biz_day_list)) ret = date_series.map(dict_date_map) return ret
def testDatesList(self): fromDate = Date(2014, 1, 31) toDate = Date(2014, 2, 28) sseCal = Calendar('China.SSE') ibCal = Calendar('China.IB') benchmarkHol = [ Date(2014, 1, 31), Date(2014, 2, 3), Date(2014, 2, 4), Date(2014, 2, 5), Date(2014, 2, 6) ] sseHolList = sseCal.holDatesList(fromDate, toDate, False) self.assertEqual(sseHolList, benchmarkHol) ibHolList = ibCal.holDatesList(fromDate, toDate, False) self.assertEqual(ibHolList, benchmarkHol) sseHolList = sseCal.holDatesList(fromDate, toDate, True) benchmarkHol = [ Date(2014, 1, 31), Date(2014, 2, 1), Date(2014, 2, 2), Date(2014, 2, 3), Date(2014, 2, 4), Date(2014, 2, 5), Date(2014, 2, 6), Date(2014, 2, 8), Date(2014, 2, 9), Date(2014, 2, 15), Date(2014, 2, 16), Date(2014, 2, 22), Date(2014, 2, 23) ] self.assertEqual(sseHolList, benchmarkHol) ibHolList = ibCal.holDatesList(fromDate, toDate, True) benchmarkHol = [ Date(2014, 1, 31), Date(2014, 2, 1), Date(2014, 2, 2), Date(2014, 2, 3), Date(2014, 2, 4), Date(2014, 2, 5), Date(2014, 2, 6), Date(2014, 2, 9), Date(2014, 2, 15), Date(2014, 2, 16), Date(2014, 2, 22), Date(2014, 2, 23) ] self.assertEqual(ibHolList, benchmarkHol) sseWorkingDayList = sseCal.bizDatesList(fromDate, toDate) d = fromDate while d <= toDate: if sseCal.isBizDay(d): self.assertTrue(d in sseWorkingDayList and d not in sseHolList) d += 1 ibWorkingDayList = ibCal.bizDatesList(fromDate, toDate) d = fromDate while d <= toDate: if ibCal.isBizDay(d): self.assertTrue(d in ibWorkingDayList and d not in ibHolList) d += 1
def testWrongInputOfHolidayCenter(self): with self.assertRaises(ValueError): _ = Calendar('NulCalendar')
def testAdvanceDate(self): referenceDate = Date(2014, 1, 31) sseCal = Calendar('China.SSE') ibCal = Calendar('China.IB') bizDayConv = BizDayConventions.Following # test null period self.assertEqual( sseCal.advanceDate(referenceDate, Period('0b'), bizDayConv), Date(2014, 2, 7)) # test negative period self.assertEqual( sseCal.advanceDate(referenceDate, Period('-5b'), bizDayConv), Date(2014, 1, 24)) # The difference is caused by Feb 8 is SSE holiday but a working day for IB market self.assertEqual( sseCal.advanceDate(referenceDate, Period('2b'), bizDayConv), Date(2014, 2, 10)) self.assertEqual( sseCal.advanceDate(referenceDate, Period('2d'), bizDayConv), Date(2014, 2, 7)) self.assertEqual( ibCal.advanceDate(referenceDate, Period('2b'), bizDayConv), Date(2014, 2, 8)) self.assertEqual( ibCal.advanceDate(referenceDate, Period('2d'), bizDayConv), Date(2014, 2, 7)) bizDayConv = BizDayConventions.ModifiedFollowing # May 31, 2014 is a holiday self.assertEqual( sseCal.advanceDate(referenceDate, Period('4m'), bizDayConv, True), Date(2014, 5, 30))
def testBasicFunctions(self): testDate = Date(2015, 7, 11) cal = Calendar('China.SSE') self.assertTrue(cal.isWeekEnd(testDate.weekday()), "{0} is expected to be a weekend".format(testDate)) testDate = Date(2015, 7, 13) self.assertTrue(not cal.isWeekEnd(testDate.weekday()), "{0} is expected not to be a weekend".format(testDate)) testDate = Date(2015, 5, 29) cal = Calendar('China.SSE') self.assertTrue( cal.isEndOfMonth(testDate), "{0} is expected to be a end of month".format(testDate)) testDate = Date(2015, 5, 1) cal = Calendar('China.SSE') endOfMonth = cal.endOfMonth(testDate) self.assertEqual( endOfMonth, Date(2015, 5, 29), "The month end of 2015/5 is expected to be {0}".format( Date(2015, 5, 29))) bizDates1 = cal.bizDaysBetween(Date(2015, 1, 1), Date(2015, 12, 31), True, False) bizDates2 = cal.bizDaysBetween(Date(2015, 12, 31), Date(2015, 1, 1), False, True) self.assertEqual(bizDates1, bizDates2)
def testCalendarDeepCopy(self): sseCal = Calendar('China.SSE') copiedCal = copy.deepcopy(sseCal) self.assertEqual(sseCal, copiedCal)
def testChinaSSE(self): # China Shanghai Securities Exchange holiday list in the year 2014 expectedHol = [ Date(2014, 1, 1), Date(2014, 1, 31), Date(2014, 2, 3), Date(2014, 2, 4), Date(2014, 2, 5), Date(2014, 2, 6), Date(2014, 4, 7), Date(2014, 5, 1), Date(2014, 5, 2), Date(2014, 6, 2), Date(2014, 9, 8), Date(2014, 10, 1), Date(2014, 10, 2), Date(2014, 10, 3), Date(2014, 10, 6), Date(2014, 10, 7), # China Shanghai Securities Exchange holiday list in the year 2015 Date(2015, 1, 1), Date(2015, 1, 2), Date(2015, 2, 18), Date(2015, 2, 19), Date(2015, 2, 20), Date(2015, 2, 23), Date(2015, 2, 24), Date(2015, 4, 6), Date(2015, 5, 1), Date(2015, 6, 22), Date(2015, 9, 3), Date(2015, 9, 4), Date(2015, 10, 1), Date(2015, 10, 2), Date(2015, 10, 5), Date(2015, 10, 6), Date(2015, 10, 7), # China Shanghai Securities Exchange holiday list in the year 2016 Date(2016, 1, 1), Date(2016, 2, 8), Date(2016, 2, 9), Date(2016, 2, 10), Date(2016, 2, 11), Date(2016, 2, 12), Date(2016, 4, 4), Date(2016, 5, 2), Date(2016, 6, 9), Date(2016, 6, 10), Date(2016, 9, 15), Date(2016, 9, 16), Date(2016, 10, 3), Date(2016, 10, 4), Date(2016, 10, 5), Date(2016, 10, 6), Date(2016, 10, 7), # China Shanghai Securities Exchange holiday list in the year 2017 Date(2017, 1, 1), Date(2017, 1, 2), Date(2017, 1, 27), Date(2017, 1, 28), Date(2017, 1, 29), Date(2017, 1, 30), Date(2017, 1, 31), Date(2017, 2, 1), Date(2017, 2, 2), Date(2017, 4, 2), Date(2017, 4, 3), Date(2017, 4, 4), Date(2017, 5, 1), Date(2017, 5, 28), Date(2017, 5, 29), Date(2017, 5, 30), Date(2017, 10, 1), Date(2017, 10, 2), Date(2017, 10, 3), Date(2017, 10, 4), Date(2017, 10, 5), Date(2017, 10, 6), Date(2017, 10, 7), Date(2017, 10, 8) ] cal = Calendar('China.SSE') for day in expectedHol: self.assertEqual( cal.isHoliday(day), True, "{0} is expected to be a holiday in {1}".format(day, cal)) self.assertEqual( cal.isBizDay(day), False, "{0} is expected not to be a working day in {1} ".format( day, cal))