/******************************************************************************* * Copyright (c) 2013 Luigi Sgro. All rights reserved. This * program and the accompanying materials are made available under the terms of * the Eclipse Public License v1.0 which accompanies this distribution, and is * available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Luigi Sgro - initial API and implementation ******************************************************************************/ package com.quantcomponents.core.calendar; import java.util.Calendar; import java.util.Date; /** * Adapter from {@link ITradingCalendar} to {@link ITradingSchedule} */ public class CalendarTradingSchedule implements ITradingSchedule { private final ITradingCalendar tradingCalendar; private final ThreadLocal<Calendar> calendars = new ThreadLocal<Calendar>() { @Override protected Calendar initialValue() { Calendar cal = Calendar.getInstance(); cal.setTimeZone(tradingCalendar.getTimeZone()); return cal; } }; private final ThreadLocal<Calendar> startCalendars = new ThreadLocal<Calendar>() { @Override protected Calendar initialValue() { Calendar cal = Calendar.getInstance(); cal.setTimeZone(tradingCalendar.getTimeZone()); return cal; } }; private final ThreadLocal<Calendar> endCalendars = new ThreadLocal<Calendar>() { @Override protected Calendar initialValue() { Calendar cal = Calendar.getInstance(); cal.setTimeZone(tradingCalendar.getTimeZone()); return cal; } }; public CalendarTradingSchedule(ITradingCalendar tradingCalendar) { this.tradingCalendar = tradingCalendar; } @Override public long intervalBeetwen(Date from, Date to) { long interval = 0L; Date firstDate = firstTradingTime(from); Date lastDate = lastTradingTime(to); Calendar cal = calendars.get(); cal.setTime(firstDate); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); for (; !cal.getTime().after(lastDate); cal.add(Calendar.DATE, 1)) { Calendar calStart = startCalendars.get(); calStart.setTime(cal.getTime()); Calendar calEnd = endCalendars.get(); calEnd.setTime(cal.getTime()); ITradingDay tradingDay = tradingCalendar.tradingDay(cal.getTime()); for (ITradingPeriod period : tradingDay.getTradingPeriods()) { calStart.set(Calendar.HOUR_OF_DAY, period.getStartHour()); calStart.set(Calendar.MINUTE, period.getStartMinute()); calEnd.set(Calendar.HOUR_OF_DAY, period.getEndHour()); calEnd.set(Calendar.MINUTE, period.getEndMinute()); if (calStart.getTime().before(lastDate) && calEnd.getTime().after(firstDate)) { long startTime = Math.max(calStart.getTime().getTime(), firstDate.getTime()); long endTime = Math.min(calEnd.getTime().getTime(), lastDate.getTime()); interval += endTime - startTime; } } } return interval; } @Override public Date firstTradingTime(Date from) { if (isTradingTime(from)) { return from; } Calendar cal = calendars.get(); cal.setTime(from); // same day ITradingDay tradingDay = tradingCalendar.tradingDay(from); ITradingPeriod[] periods = tradingDay.getTradingPeriods(); for (int i = 0; i < periods.length; i++) { ITradingPeriod period = periods[i]; int hour = cal.get(Calendar.HOUR_OF_DAY); int minute = cal.get(Calendar.MINUTE); // find start of first trading period after startCalendar if (period.getStartHour() > hour || period.getStartHour() == hour && period.getStartMinute() >= minute) { cal.set(Calendar.HOUR_OF_DAY, period.getStartHour()); cal.set(Calendar.MINUTE, period.getStartMinute()); return cal.getTime(); } } // following days cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); while (!cal.after(tradingCalendar.getEndDate())) { cal.add(Calendar.DATE, 1); tradingDay = tradingCalendar.tradingDay(cal.getTime()); periods = tradingDay.getTradingPeriods(); if (periods.length > 0) { ITradingPeriod firstPeriod = periods[0]; cal.set(Calendar.HOUR_OF_DAY, firstPeriod.getStartHour()); cal.set(Calendar.MINUTE, firstPeriod.getStartMinute()); return cal.getTime(); } } return null; } @Override public Date lastTradingTime(Date to) { if (isTradingTime(to)) { return to; } Calendar cal = calendars.get(); cal.setTime(to); // same day ITradingDay tradingDay = tradingCalendar.tradingDay(to); ITradingPeriod[] periods = tradingDay.getTradingPeriods(); for (int i = periods.length - 1; i >= 0; i--) { ITradingPeriod period = periods[i]; int hour = cal.get(Calendar.HOUR_OF_DAY); int minute = cal.get(Calendar.MINUTE); // find end of last trading period before startCalendar if (period.getEndHour() < hour || period.getEndHour() == hour && period.getEndMinute() <= minute) { cal.set(Calendar.HOUR_OF_DAY, period.getEndHour()); cal.set(Calendar.MINUTE, period.getEndMinute()); return cal.getTime(); } } // previous days cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); while (!cal.before(tradingCalendar.getStartDate())) { cal.add(Calendar.DATE, -1); tradingDay = tradingCalendar.tradingDay(cal.getTime()); periods = tradingDay.getTradingPeriods(); if (periods.length > 0) { ITradingPeriod lastPeriod = periods[periods.length - 1]; cal.set(Calendar.HOUR_OF_DAY, lastPeriod.getEndHour()); cal.set(Calendar.MINUTE, lastPeriod.getEndMinute()); return cal.getTime(); } } return null; } @Override public boolean isTradingTime(Date time) { ITradingDay tradingDay = tradingCalendar.tradingDay(time); Calendar cal = calendars.get(); cal.setTime(time); for (ITradingPeriod period : tradingDay.getTradingPeriods()) { if (period.contains(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE))) { return true; } } return false; } }