/*
* Copyright (c) 2004-2011 Marco Maccaferri and others.
* 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:
* Marco Maccaferri - initial API and implementation
*/
package org.eclipsetrader.core.feed;
import java.util.Calendar;
import java.util.Date;
import java.util.Observable;
/**
* General purpose bar generator.
*
* @since 1.0
*/
public class BarGenerator extends Observable {
private TimeSpan timeSpan;
Date dateOpen;
Double open;
Double high;
Double low;
Double close;
Long volume;
Date dateClose;
private Calendar calendar = Calendar.getInstance();
/**
* Constructs a new instance of the generator using the given time span to aggregate trades.
*
* @param timeSpan the aggregation time span.
*/
public BarGenerator(TimeSpan timeSpan) {
this.timeSpan = timeSpan;
}
/**
* Adds a new trade to the current bar.
* <p>If the new trade causes a pending bar to close (the trade time is past the expected close time)
* the method returns the closed bar, otherwise it returns <code>null</code>.</p>
*
* @param trade the trade to add.
*/
public void addTrade(ITrade trade) {
if (trade.getTime() == null) {
return;
}
calendar.setTime(trade.getTime());
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
if (dateOpen != null && dateClose != null) {
Date time = calendar.getTime();
if (!time.before(dateOpen) && time.before(dateClose)) {
if (high == null || trade.getPrice() > high) {
high = trade.getPrice();
}
if (low == null || trade.getPrice() < low) {
low = trade.getPrice();
}
close = trade.getPrice();
if (trade.getSize() != null) {
volume = volume != null ? volume + trade.getSize() : trade.getSize();
}
}
if (!time.before(dateClose)) {
setChanged();
notifyObservers(new Bar(dateOpen, timeSpan, open, high, low, close, volume));
dateOpen = null;
}
}
if (dateOpen == null) {
int round = calendar.get(Calendar.MINUTE) % timeSpan.getLength();
calendar.add(Calendar.MINUTE, -round);
dateOpen = calendar.getTime();
calendar.add(Calendar.MINUTE, timeSpan.getLength());
dateClose = calendar.getTime();
open = trade.getPrice();
high = trade.getPrice();
low = trade.getPrice();
close = trade.getPrice();
volume = trade.getSize();
setChanged();
notifyObservers(new BarOpen(dateOpen, timeSpan, open));
}
}
/**
* Forces the current pending bar to close.
*/
public void forceBarClose() {
if (dateOpen == null) {
return;
}
setChanged();
notifyObservers(new Bar(dateOpen, timeSpan, open, high, low, close, volume));
dateOpen = null;
}
/**
* Gets if the there is a pending bar that is expired (current time is past the expected
* close time).
*
* @return <code>true</code> if there is a pending expired bar.
*/
public boolean isBarExpired() {
if (dateOpen == null || dateClose == null) {
return false;
}
return new Date().after(dateClose);
}
}