### Eclipse Workspace Patch 1.0 #P jquantlib Index: src/test/java/org/jquantlib/time/calendars/HongKongTest.java =================================================================== --- src/test/java/org/jquantlib/time/calendars/HongKongTest.java (revision 0) +++ src/test/java/org/jquantlib/time/calendars/HongKongTest.java (revision 0) @@ -0,0 +1,201 @@ +package org.jquantlib.time.calendars; + +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; + +import org.jquantlib.util.Date; +import org.jquantlib.util.DateFactory; +import org.junit.Test; + +/** + * Test base on information from these web pages: + * http://www.hkex.com.hk/tradinfo/tradcal/cal06.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal07.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal08.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal09.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal10.htm + * + * @author henry + * + */ +public class HongKongTest { + + private HongKong hk = HongKong.getCalendar(HongKong.Market.HKEx); + + private void checkDays(int year, int[][] tradeDays) { + Date d = DateFactory.getFactory().getDate(1, 1, year); + + int day, month; + int[] days; + while (d.getYear() == year) { + day = d.getDayOfMonth(); + month = d.getMonth(); + days = tradeDays[month - 1]; + if (Arrays.binarySearch(days, day) >= 0) { + assertTrue("Error for business day: " + day + "-" + month + "-" + + year, hk.isBusinessDay(d)); + } else { + assertTrue("Error for holiday " + day + "-" + month + "-" + + year, hk.isHoliday(d)); + } + + d.increment(); + } + } + + @Test + public void test2006() { + int[][] tradeDays = { + { 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27 }, + { 1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, + 24, 27, 28 }, + { 1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, + 24, 27, 28, 29, 30, 31 }, + { 3, 4, 6, 7, 10, 11, 12, 13, 18, 19, 20, 21, 24, 25, 26, 27, + 28 }, + { 2, 3, 4, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, + 25, 26, 29, 30 }, + { 1, 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, + 26, 27, 28, 29, 30 }, + { 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, + 25, 26, 27, 28, 31 }, + { 1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, + 24, 25, 28, 29, 30, 31 }, + { 1, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, + 26, 27, 28, 29 }, + { 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27, 31 }, + { 1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, + 24, 27, 28, 29, 30 }, + { 1, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 27, + 28, 29 } }; + + checkDays(2006, tradeDays); + } + + @Test + public void test2007() { + int[][] tradeDays = { + { 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, + 25, 26, 29, 30, 31 }, + { 1, 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 21, 22, 23, 26, 27, + 28 }, + { 1, 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, + 26, 27, 28, 29, 30 }, + { 2, 3, 4, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, 25, 26, + 27, 30 }, + { 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 25, + 28, 29, 30, 31 }, + { 1, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 20, 21, 22, 25, 26, + 27, 28, 29 }, + { 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27, 30, 31 }, + { 1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, + 24, 27, 28, 29, 30, 31 }, + { 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, + 25, 27, 28 }, + { 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 22, 23, 24, 25, + 26, 29, 30, 31 }, + { 1, 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, + 26, 27, 28, 29, 30 }, + { 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, + 27, 28, 31 } }; + + checkDays(2007, tradeDays); + } + + @Test + public void test2008() { + int[][] tradeDays = { + { 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, + 25, 28, 29, 30, 31 }, + { 1, 4, 5, 6, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, 26, + 27, 28, 29 }, + { 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 25, 26, + 27, 28, 31 }, + { 1, 2, 3, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, + 25, 28, 29, 30 }, + { 2, 5, 6, 7, 8, 9, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, + 28, 29, 30 }, + { 2, 3, 4, 5, 6, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27, 30 }, + { 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, + 25, 28, 29, 30, 31 }, + { 1, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, + 26, 27, 28, 29 }, + { 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 16, 17, 18, 19, 22, 23, 24, + 25, 26, 29, 30 }, + { 2, 3, 6, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, + 27, 28, 29, 30, 31 }, + { 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, + 25, 26, 27, 28 }, + { 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, + 24, 29, 30, 31 } }; + + checkDays(2008, tradeDays); + } + + @Test + public void test2009() { + int[][] tradeDays = { + { 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 29, + 30 }, + { 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27 }, + { 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27, 30, 31 }, + { 1, 2, 3, 6, 7, 8, 9, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, + 28, 29, 30 }, + { 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, + 26, 27, 29 }, + { 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, + 24, 25, 26, 29, 30 }, + { 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, + 27, 28, 29, 30, 31 }, + { 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, + 25, 26, 27, 28, 31 }, + { 1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, + 24, 25, 28, 29, 30 }, + { 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 27, + 28, 29, 30 }, + { 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27, 30 }, + { 1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, + 24, 28, 29, 30, 31 } }; + + checkDays(2009, tradeDays); + } + + @Test + public void test2010() { + int[][] tradeDays = { + { 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, + 26, 27, 28, 29 }, + { 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 17, 18, 19, 22, 23, 24, 25, + 26 }, + { 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, + 24, 25, 26, 29, 30, 31, }, + { 1, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, + 28, 29, 30 }, + { 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 24, 25, + 26, 27, 28, 31 }, + { 1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 21, 22, 23, 24, + 25, 28, 29, 30 }, + { 2, 5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, + 27, 28, 29, 30 }, + { 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, + 25, 26, 27, 30, 31 }, + { 1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 24, + 27, 28, 29, 30 }, + { 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, + 26, 27, 28, 29 }, + { 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, + 24, 25, 26, 29, 30 }, + { 1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, + 24, 28, 29, 30, 31 } }; + + checkDays(2010, tradeDays); + } +} Index: src/main/java/org/jquantlib/time/calendars/HongKong.java =================================================================== --- src/main/java/org/jquantlib/time/calendars/HongKong.java (revision 1302) +++ src/main/java/org/jquantlib/time/calendars/HongKong.java (working copy) @@ -23,6 +23,7 @@ package org.jquantlib.time.calendars; import static org.jquantlib.time.Weekday.MONDAY; +import static org.jquantlib.time.Weekday.TUESDAY; import static org.jquantlib.util.Month.APRIL; import static org.jquantlib.util.Month.DECEMBER; import static org.jquantlib.util.Month.FEBRUARY; @@ -36,6 +37,7 @@ import org.jquantlib.time.Calendar; import org.jquantlib.time.Weekday; import org.jquantlib.time.WesternCalendar; +import org.jquantlib.time.calendars.DelegateCalendar; import org.jquantlib.util.Date; import org.jquantlib.util.Month; @@ -115,57 +117,41 @@ Month m = date.getMonthEnum(); int y = date.getYear(); int em = easterMonday(y); - + + /* + * References: + * http://www.gov.hk/en/about/abouthk/holiday/ + * http://www.legislation.gov.hk/BLIS_IND.NSF/E1BF50C09A33D3DC482564840019D2F4/EC16AF2AF1A319BD88256489000ADF4E?OpenDocument + * http://www.hkex.com.hk/tradinfo/tradcal/cal06.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal07.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal08.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal09.htm + * http://www.hkex.com.hk/tradinfo/tradcal/cal10.htm + */ if (isWeekend(w) // New Year's Day - || ((d == 1 || ((d == 2 || d == 3) && w == MONDAY)) && m == JANUARY) - // Ching Ming Festival - || (d == 5 && m == APRIL) + || ((d == 1 || (d == 2 && w == MONDAY)) && m == JANUARY) // Good Friday || (dd == em-3) // Easter Monday || (dd == em) // Labor Day - || (d == 1 && m == MAY) + || ((d == 1 || (d == 2 && w == MONDAY)) && m == MAY) // SAR Establishment Day - || ((d == 1 || ((d == 2 || d == 3) && w == MONDAY)) && m == JULY) + || ((d == 1 || (d == 2 && w == MONDAY)) && m == JULY) // National Day - || ((d == 1 || ((d == 2 || d == 3) && w == MONDAY)) && m == OCTOBER) + || ((d == 1 || (d == 2 && w == MONDAY)) && m == OCTOBER) // Christmas Day - || (d == 25 && m == DECEMBER) - // Boxing Day - || ((d == 26 || ((d == 27 || d == 28) && w == MONDAY)) && m == DECEMBER && y<2009)) + || ((d == 25 || (d == 27 && w == TUESDAY)) && m == DECEMBER) + // First Weekday After Christmas Day + || ((d == 26 || (d == 27 && w == MONDAY)) && m == DECEMBER)) return false; - if (y == 2004) { - return ! (// Lunar New Year - ((d==22 || d==23 || d==24) && m == JANUARY) - // Buddha's birthday - || (d == 26 && m == MAY) - // Tuen NG festival - || (d == 22 && m == JUNE) - // Mid-autumn festival - || (d == 29 && m == SEPTEMBER) - // Chung Yeung - || (d == 29 && m == SEPTEMBER)); - } - - else if (y == 2005) { - return ! (// Lunar New Year - ((d==9 || d==10 || d==11) && m == FEBRUARY) - // Buddha's birthday - || (d == 16 && m == MAY) - // Tuen NG festival - || (d == 11 && m == JUNE) - // Mid-autumn festival - || (d == 19 && m == SEPTEMBER) - // Chung Yeung festival - || (d == 11 && m == OCTOBER)); - } - - else if (y == 2006) { + if (y == 2006) { return ! (// Lunar New Year ((d >= 28 && d <= 31) && m == JANUARY) + // Ching Ming Festival + || (d == 5 && m == APRIL) // Buddha's birthday || (d == 5 && m == MAY) // Tuen NG festival @@ -179,6 +165,8 @@ else if (y == 2007) { return ! (// Lunar New Year ((d >= 17 && d <= 20) && m == FEBRUARY) + // Ching Ming Festival + || (d == 5 && m == APRIL) // Buddha's birthday || (d == 24 && m == MAY) // Tuen NG festival @@ -204,30 +192,28 @@ || (d == 7 && m == OCTOBER)); } - else if (y == 2008) { - return ! (// Lunar New Year - ((d >= 7 && d <= 9) && m == FEBRUARY) - // Ching Ming Festival - || (d == 4 && m == APRIL) - // Buddha's birthday - || (d == 12 && m == MAY) - // Tuen NG festival - || (d == 9 && m == JUNE) - // Mid-autumn festival - || (d == 15 && m == SEPTEMBER) - // Chung Yeung festival - || (d == 7 && m == OCTOBER)); - } - - else if (y == 2009) { - return ! ( - ((d >= 26 && d <= 28) && m == JANUARY) // Lunar New Year - //--- || (d == 4 && m == APRIL) // Ching Ming Festival - //--- || (d == 12 && m == MAY) // Buddha's birthday - || (d == 28 && m == MAY) // Tuen NG festival - || (d == 26 && m == OCTOBER)); // Chung Yeung Festival - } - + else if (y == 2009) { + return !( // Lunar New Year + ((d >= 26 && d <= 28) && m == JANUARY) + // Tuen NG festival + || (d == 28 && m == MAY) + // Chung Yeung Festival + || (d == 26 && m == OCTOBER)); + } + + else if (y == 2010) { + return !(// Lunar New Year + ((d >= 15 && d <= 16) && m == FEBRUARY) + // The day following Ching Ming Festival + || (d == 6 && m == APRIL) + // The Buddha's Birthday + || (d == 21 && m == MAY) + // Tuen Ng Festival + || (d == 16 && m == JUNE) + // The day following Chinese Mid-Autumn Festival + || (d == 23 && m == SEPTEMBER)); + } + else throw new IllegalArgumentException(YEAR_OUT_OF_RANGE); } @@ -237,6 +223,18 @@ } + public boolean isHalfBusinessDay(Date date) { + int d = date.getDayOfMonth(); + Month m = date.getMonthEnum(); + + if ((d == 24 || d == 31) && m == DECEMBER) { + return true; + } else if (d == 6 && m == FEBRUARY && date.getYear() == 2008) { + return true; + } + + return false; + } }