below is my code. i believe this is a good start. it almost works. i cant seem to figure out whats wrong with it. the code seems simple. please try it out on your charts.
here is the signature for the constructor. this is all you need
Code: Select all
public IntradayMarketTimeline(long sundayStart, long sundayEnd,
long mondayStart, long mondayEnd,
long tuesdayStart, long tuesdayEnd,
long wednesdayStart, long wednesdayEnd,
long thursdayStart, long thursdayEnd,
long fridayStart, long fridayEnd,
long saturdayStart, long saturdayEnd)
Code: Select all
IntradayMarketTimeline testedObject = new IntradayMarketTimeline(
0L,
0L,
34200000L,
57600000L,
34200000L,
57600000L,
34200000L,
57600000L,
34200000L,
57600000L,
34200000L,
57600000L,
0L,
0L);
the values for the start and stop times are the number of milliseconds from 00:00 for that day. so in these examples, saturday and sunday have start and stop times of 0 and 0 because we dont want activities on these days.
the rest of the days start at 9:30 am and stop at 4:00pm. 9:30 am is 9.5 hours * 60 min * 60 sec * 1000 millisec = 34200000 milliseconds from 00:00 for that day
likewise 4:00pm is 16 hours * 60 min .... = 57600000 milliseconds from 00:00 for that day
below is the code. i think my algorithm is simple. some of my comments might be lacking. feel free to ask questions.
Code: Select all
import org.jfree.chart.axis.Timeline;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.Calendar;
import java.util.ArrayList;
/**
*
*/
public class IntradayMarketTimeline implements Timeline {
private long sundayStart = 0;
private long sundayEnd = 0;
private long mondayStart = 0;
private long mondayEnd = 0;
private long tuesdayStart = 0;
private long tuesdayEnd = 0;
private long wednesdayStart = 0;
private long wednesdayEnd = 0;
private long thursdayStart = 0;
private long thursdayEnd = 0;
private long fridayStart = 0;
private long fridayEnd = 0;
private long saturdayStart = 0;
private long saturdayEnd = 0;
private long sundayActive = 0;
private long mondayActive = 0;
private long tuesdayActive = 0;
private long wednesdayActive = 0;
private long thursdayActive = 0;
private long fridayActive = 0;
private long saturdayActive = 0;
private long activeTimePerWeek = 0;
//private long closedTimePerWeek = 0;
private static final long MILLIS_PER_WEEK = 7 * 24 * 60 * 60 * 1000;
private static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
//specify the start and end times for the market
//times are given in milliseconds in relation to 00:00 for that day.
//so a start time of 01:00 would be 1 hour * 60 minutes * 60 seconds * 1000 milliseconds
public IntradayMarketTimeline(long sundayStart, long sundayEnd,
long mondayStart, long mondayEnd,
long tuesdayStart, long tuesdayEnd,
long wednesdayStart, long wednesdayEnd,
long thursdayStart, long thursdayEnd,
long fridayStart, long fridayEnd,
long saturdayStart, long saturdayEnd) {
this.sundayStart = sundayStart;
this.sundayEnd = sundayEnd;
this.mondayStart = mondayStart;
this.mondayEnd = mondayEnd;
this.tuesdayStart = tuesdayStart;
this.tuesdayEnd = tuesdayEnd;
this.wednesdayStart = wednesdayStart;
this.wednesdayEnd = wednesdayEnd;
this.thursdayStart = thursdayStart;
this.thursdayEnd = thursdayEnd;
this.fridayStart = fridayStart;
this.fridayEnd = fridayEnd;
this.saturdayStart = saturdayStart;
this.saturdayEnd = saturdayEnd;
//calculate the amount of time the market is open during each day
this.sundayActive = this.sundayEnd - this.sundayStart;
this.mondayActive = this.mondayEnd - this.mondayStart;
this.tuesdayActive = this.tuesdayEnd - this.tuesdayStart;
this.wednesdayActive = this.wednesdayEnd - this.wednesdayStart;
this.thursdayActive = this.thursdayEnd - this.thursdayStart;
this.fridayActive = this.fridayEnd - this.fridayStart;
this.saturdayActive = this.saturdayEnd - this.saturdayStart;
this.activeTimePerWeek = this.sundayActive +
this.mondayActive + this.tuesdayActive +
this.wednesdayActive + this.thursdayActive +
this.fridayActive + this.saturdayActive;
//calculate the amount of time the market is closed each week
//this.closedTimePerWeek = this.MILLIS_PER_WEEK - this.activeTimePerWeek;
}
/**
* Translates a millisecond (as defined by java.util.Date) into an index
* along this timeline.
*
* @param target - the milliseconds of a date to convert
*
* @return A timeline value.
*/
public long toTimelineValue(long currentDayMillis) {
//
//find out the day of the week the current day is
//SUNDAY = 1,...SATURDAY = 7
Calendar currentDay = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
currentDay.setTimeInMillis(currentDayMillis);
//a list of the days from the current date until last thursday 00:00
//which includes thursday itself from (00:00,23:59)
ArrayList<Integer> daysFromThursday = new ArrayList();
Calendar lastThursday = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
lastThursday.setTimeInMillis(currentDayMillis);
//move backwards in time until you hit a wednesday
while (lastThursday.get(Calendar.DAY_OF_WEEK) != Calendar.THURSDAY) {
//add this day to the list
daysFromThursday.add(new Integer(lastThursday.get(Calendar.DAY_OF_WEEK)));
//
//move back one more day
lastThursday.add(Calendar.DATE, -1);
}
//
//add thursday to the list
daysFromThursday.add(new Integer(Calendar.THURSDAY));
//adjust Calendar to the beginning of last thursday
lastThursday.set(Calendar.MILLISECOND, 0);
lastThursday.set(Calendar.SECOND, 0);
lastThursday.set(Calendar.MINUTE, 0);
lastThursday.set(Calendar.HOUR_OF_DAY, 0);
//get the milliseconds for the beginning of last Thursday
long lastThursdayMillis = lastThursday.getTimeInMillis();
//because Jan 1, 1970 was a Thursday, lastThursdayMillis
//gives an even # of weeks from Jan 1, 1970 until lastThursdayMillis.
//so subtract the (down time per week * the
//number of weeks) since Jan 1, 1970
//the number of weeks since Jan 1, 1970
int numberOfWeeks = (int) Math.round((new Long(lastThursdayMillis/this.MILLIS_PER_WEEK)).doubleValue());
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
TimeZone.setDefault(TimeZone.getDefault());
//get the timeline value for the number of millis since
//Jan 1, 1970 to last thursday, by multiplying the number of weeks
//since Jan 1, 1970 by the amount of active milliseconds per week
long timelineValue = numberOfWeeks * this.activeTimePerWeek;
//
//add the amount of active millseconds for the current day
//of the given time
long millisOfCurrentDay = currentDay.get(Calendar.HOUR_OF_DAY) * 3600000 +
currentDay.get(Calendar.MINUTE) * 60000 +
currentDay.get(Calendar.SECOND) * 1000 +
currentDay.get(Calendar.MILLISECOND);
long startOfCurrentDay = this.getStartTime(currentDay.get(Calendar.DAY_OF_WEEK));
long endOfCurrentDay = this.getEndTime(currentDay.get(Calendar.DAY_OF_WEEK));
Integer.toString(currentDay.get(Calendar.MINUTE)) + " " +
Integer.toString(currentDay.get(Calendar.SECOND))+":"+
Integer.toString(currentDay.get(Calendar.MILLISECOND)));
if (millisOfCurrentDay >= startOfCurrentDay && millisOfCurrentDay <= endOfCurrentDay) {
timelineValue += millisOfCurrentDay - startOfCurrentDay;
}
//get the size of the list
int listSize = daysFromThursday.size();
//add the active time since last thursday, skipping the first day since
//we already took care of that
for (int i = 1; i < listSize; i++) {
int day = ((Integer) daysFromThursday.get(i)).intValue();
timelineValue += this.getActiveTimePerDay(day);
}
return timelineValue;
}
/**
* Translates a date into a value on this timeline.
*
* @param date the date.
*
* @return A timeline value
*/
public long toTimelineValue(Date date) {
//normalize to GMT
return this.toTimelineValue(date.getTimezoneOffset() + date.getTime());
}
/**
* Translates a value relative to this timeline into a domain value. The
* domain value obtained by this method is not always the same domain value
* that could have been supplied to
* translateDomainValueToTimelineValue(domainValue).
* This is because the original tranformation may not be complete
* reversable.
*
* @see org.jfree.chart.axis.SegmentedTimeline
*
* @param timelineValue a timeline value.
*
* @return A domain value.
*/
public long toMillisecond(long timelineValue) {
if (this.activeTimePerWeek == 0L)
return 0;
//starting from Jan 1, 1970 work backwards.
//find out the number of whole weeks in the timelineValue
Long l = new Long(timelineValue/this.activeTimePerWeek);
int numWeeks = (int) Math.floor(l.doubleValue());
//the amount of time left on the timeline from the last thursday
long timeLeftSinceThursday = timelineValue - (numWeeks * this.activeTimePerWeek);
int day = Calendar.THURSDAY;
int numDays = 0;
//from last friday until the current day
//if the amount of time left is greater than
//the active time for that day, increment the number of
//days and subtract from the time left
while (numDays < 7) {
if (day == Calendar.SUNDAY) {
if (timeLeftSinceThursday > this.sundayActive) {
timeLeftSinceThursday -= this.sundayActive;
numDays++;
}
else {
break;
}
}
else if (day == Calendar.MONDAY) {
if (timeLeftSinceThursday > this.mondayActive) {
timeLeftSinceThursday -= this.mondayActive;
numDays++;
}
else {
break;
}
}
else if (day == Calendar.TUESDAY) {
if (timeLeftSinceThursday > this.tuesdayActive) {
timeLeftSinceThursday -= this.tuesdayActive;
numDays++;
}
else {
break;
}
}
else if (day == Calendar.WEDNESDAY) {
if (timeLeftSinceThursday > this.wednesdayActive) {
timeLeftSinceThursday -= this.wednesdayActive;
numDays++;
}
else {
break;
}
}
else if (day == Calendar.THURSDAY) {
if (timeLeftSinceThursday > this.thursdayActive) {
timeLeftSinceThursday -= this.thursdayActive;
numDays++;
//thursday numDays = " + Integer.toString(numDays));
}
else {
break;
}
}
else if (day == Calendar.FRIDAY) {
if (timeLeftSinceThursday > this.fridayActive) {
timeLeftSinceThursday -= this.fridayActive;
numDays++;
}
else {
break;
}
}
else if (day == Calendar.SATURDAY) {
if (timeLeftSinceThursday > this.saturdayActive) {
timeLeftSinceThursday -= this.saturdayActive;
numDays++;
}
else {
break;
}
}
day = this.nextDay(day);
}
long millis = numWeeks * this.MILLIS_PER_WEEK +
numDays * this.MILLIS_PER_DAY +
this.getStartTime(day) + timeLeftSinceThursday;
return millis;
}
/**
* Returns <code>true</code> if a value is contained in the timeline values.
*
* @param millisecond the millisecond.
*
* @return <code>true</code> if value is contained in the timeline and
* <code>false</code> otherwise.
*/
public boolean containsDomainValue(long millisecond) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTimeInMillis(millisecond);
return isActiveDate(cal);
}
/**
* Returns <code>true</code> if a date is contained in the timeline values.
*
* @param date the date to verify.
*
* @return <code>true</code> if value is contained in the timeline and
* <code>false</code> otherwise.
*/
public boolean containsDomainValue(Date date) {
//normalize to GMT
return this.containsDomainValue(date.getTimezoneOffset() + date.getTime());
}
/**
* Returns <code>true</code> if a range of values are contained in the
* timeline.
*
* @param fromMillisecond the start of the range to verify.
* @param toMillisecond the end of the range to verify.
*
* @return <code>true</code> if the range is contained in the timeline or
* <code>false</code> otherwise
*/
public boolean containsDomainRange(long fromMillisecond, long toMillisecond) {
Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal1.setTimeInMillis(fromMillisecond);
cal2.setTimeInMillis(toMillisecond);
return this.isActiveDate(cal1, cal2);
}
/**
* Returns <code>true</code> if a range of dates are contained in the
* timeline.
*
* @param fromDate the start of the range to verify.
* @param toDate the end of the range to verify.
*
* @return <code>true</code> if the range is contained in the timeline or
* <code>false</code> otherwise
*/
public boolean containsDomainRange(Date fromDate, Date toDate) {
//normalize to GMT
return this.containsDomainRange(fromDate.getTimezoneOffset() + fromDate.getTime(), toDate.getTimezoneOffset() + toDate.getTime());
}
private long getActiveTimePerDay(int day) {
long closedTime = 0;
if (day == Calendar.SUNDAY) {
closedTime = this.sundayActive;
}
else if (day == Calendar.MONDAY) {
closedTime = this.mondayActive;
}
else if (day == Calendar.TUESDAY) {
closedTime = this.tuesdayActive;
}
else if (day == Calendar.WEDNESDAY) {
closedTime = this.wednesdayActive;
}
else if (day == Calendar.THURSDAY) {
closedTime = this.thursdayActive;
}
else if (day == Calendar.FRIDAY) {
closedTime = this.fridayActive;
}
else if (day == Calendar.SATURDAY) {
closedTime = this.saturdayActive;
}
return closedTime;
}
private long getStartTime(int day) {
long startTime = 0;
if (day == Calendar.SUNDAY) {
startTime = this.sundayStart;
}
else if (day == Calendar.MONDAY) {
startTime = this.mondayStart;
}
else if (day == Calendar.TUESDAY) {
startTime = this.tuesdayStart;
}
else if (day == Calendar.WEDNESDAY) {
startTime = this.wednesdayStart;
}
else if (day == Calendar.THURSDAY) {
startTime = this.thursdayStart;
}
else if (day == Calendar.FRIDAY) {
startTime = this.fridayStart;
}
else if (day == Calendar.SATURDAY) {
startTime = this.saturdayStart;
}
return startTime;
}
private long getEndTime(int day) {
long endTime = 0;
if (day == Calendar.SUNDAY) {
endTime = this.sundayEnd;
}
else if (day == Calendar.MONDAY) {
endTime = this.mondayEnd;
}
else if (day == Calendar.TUESDAY) {
endTime = this.tuesdayEnd;
}
else if (day == Calendar.WEDNESDAY) {
endTime = this.wednesdayEnd;
}
else if (day == Calendar.THURSDAY) {
endTime = this.thursdayEnd;
}
else if (day == Calendar.FRIDAY) {
endTime = this.fridayEnd;
}
else if (day == Calendar.SATURDAY) {
endTime = this.saturdayEnd;
}
return endTime;
}
private boolean isActiveDate(Calendar cal) {
int day = cal.get(Calendar.DAY_OF_WEEK);
long timeSinceStart = cal.get(Calendar.HOUR_OF_DAY) * 3600000 +
cal.get(Calendar.MINUTE) * 60000 +
cal.get(Calendar.SECOND) * 1000;
if (day == Calendar.SUNDAY) {
return (timeSinceStart > this.sundayStart && timeSinceStart < this.sundayEnd);
}
else if (day == Calendar.MONDAY) {
return (timeSinceStart > this.mondayStart && timeSinceStart < this.mondayEnd);
}
else if (day == Calendar.TUESDAY) {
return (timeSinceStart > this.tuesdayStart && timeSinceStart < this.tuesdayEnd);
}
else if (day == Calendar.WEDNESDAY) {
return (timeSinceStart > this.wednesdayStart && timeSinceStart < this.wednesdayEnd);
}
else if (day == Calendar.THURSDAY) {
return (timeSinceStart > this.thursdayStart && timeSinceStart < this.thursdayEnd);
}
else if (day == Calendar.FRIDAY) {
return (timeSinceStart > this.fridayStart && timeSinceStart < this.fridayEnd);
}
else if (day == Calendar.SATURDAY) {
return (timeSinceStart > this.saturdayStart && timeSinceStart < this.saturdayEnd);
}
else {
return false;
}
}
private boolean isActiveDate(Calendar cal, Calendar cal2) {
int day = cal.get(Calendar.DAY_OF_WEEK);
long timeSinceStart = cal.get(Calendar.HOUR_OF_DAY) * 3600000 +
cal.get(Calendar.MINUTE) * 60000 +
cal.get(Calendar.SECOND) * 1000;
boolean firstDate = false;
if (day == Calendar.SUNDAY) {
firstDate = (timeSinceStart > this.sundayStart && timeSinceStart < this.sundayEnd);
}
else if (day == Calendar.MONDAY) {
firstDate = (timeSinceStart > this.mondayStart && timeSinceStart < this.mondayEnd);
}
else if (day == Calendar.TUESDAY) {
firstDate = (timeSinceStart > this.tuesdayStart && timeSinceStart < this.tuesdayEnd);
}
else if (day == Calendar.WEDNESDAY) {
firstDate = (timeSinceStart > this.wednesdayStart && timeSinceStart < this.wednesdayEnd);
}
else if (day == Calendar.THURSDAY) {
firstDate = (timeSinceStart > this.thursdayStart && timeSinceStart < this.thursdayEnd);
}
else if (day == Calendar.FRIDAY) {
firstDate = (timeSinceStart > this.fridayStart && timeSinceStart < this.fridayEnd);
}
else if (day == Calendar.SATURDAY) {
firstDate = (timeSinceStart > this.saturdayStart && timeSinceStart < this.saturdayEnd);
}
else {
firstDate = false;
}
int day2 = cal2.get(Calendar.DAY_OF_WEEK);
timeSinceStart = cal2.get(Calendar.HOUR_OF_DAY) * 3600000 +
cal2.get(Calendar.MINUTE) * 60000 +
cal2.get(Calendar.SECOND) * 1000;
boolean secondDate = false;
if (day2 == Calendar.SUNDAY) {
secondDate = (timeSinceStart > this.sundayStart && timeSinceStart < this.sundayEnd);
}
else if (day2 == Calendar.MONDAY) {
secondDate = (timeSinceStart > this.mondayStart && timeSinceStart < this.mondayEnd);
}
else if (day2 == Calendar.TUESDAY) {
secondDate = (timeSinceStart > this.tuesdayStart && timeSinceStart < this.tuesdayEnd);
}
else if (day2 == Calendar.WEDNESDAY) {
secondDate = (timeSinceStart > this.wednesdayStart && timeSinceStart < this.wednesdayEnd);
}
else if (day2 == Calendar.THURSDAY) {
secondDate = (timeSinceStart > this.thursdayStart && timeSinceStart < this.thursdayEnd);
}
else if (day2 == Calendar.FRIDAY) {
secondDate = (timeSinceStart > this.fridayStart && timeSinceStart < this.fridayEnd);
}
else if (day2 == Calendar.SATURDAY) {
secondDate = (timeSinceStart > this.saturdayStart && timeSinceStart < this.saturdayEnd);
}
else {
secondDate = false;
}
return (firstDate && secondDate);
}
private int nextDay(int day) {
day++;
day = day % 7;
return day;
}
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
IntradayMarketTimeline testedObject = new IntradayMarketTimeline(
0L,
0L,
34200000L,
57600000L,
34200000L,
57600000L,
34200000L,
57600000L,
34200000L,
57600000L,
34200000L,
57600000L,
0L,
0L);
//one week + 1 day + 10:48am
//604800000
//86400000
System.out.println("millisecond -> timeline" +Long.toString(
IntradayMarketTimeline.MILLIS_PER_DAY +
IntradayMarketTimeline.MILLIS_PER_WEEK +
+ 38880000L));
//leads to 121680000 milliseconds in timeline time
System.out.println(Long.toString(testedObject.toTimelineValue(
IntradayMarketTimeline.MILLIS_PER_DAY +
IntradayMarketTimeline.MILLIS_PER_WEEK +
+ 38880000L)));
System.out.println("timeline -> millisecond "+Long.toString(testedObject.toMillisecond(145080000L)));
}
}