package storm.applications.bolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import java.util.HashMap;
import java.util.Map;
import org.joda.time.DateTime;
import org.joda.time.DateTimeComparator;
import static storm.applications.constants.BargainIndexConstants.*;
/**
* Calculates the VWAP (Volume Weighted Average Price) throughout the day for each
* stock symbol. When the first quote from following day appears, the old calculation
* is thrown away.
*
* @author mayconbordin
*/
public class VwapBolt extends AbstractBolt {
private static final DateTimeComparator dateOnlyComparator = DateTimeComparator.getDateOnlyInstance();
private Map<String, Vwap> stocks;
private String period;
@Override
public Fields getDefaultFields() {
return new Fields(Field.STOCK, Field.VWAP, Field.START_DATE, Field.END_DATE);
}
@Override
public void initialize() {
period = config.getString(Conf.VWAP_PERIOD, Periodicity.DAILY);
stocks = new HashMap<>();
}
@Override
public void execute(Tuple input) {
String stock = input.getStringByField(Field.STOCK);
double price = (double) input.getDoubleByField(Field.PRICE);
int volume = (int) input.getIntegerByField(Field.VOLUME);
DateTime date = (DateTime) input.getValueByField(Field.DATE);
int inteval = input.getIntegerByField(Field.INTERVAL);
Vwap vwap = stocks.get(stock);
if (withinPeriod(vwap, date)) {
vwap.update(volume, price, date.plusSeconds(inteval));
collector.emit(input, new Values(stock, vwap.getVwap(), vwap.getStartDate(), vwap.getEndDate()));
} else {
if (vwap != null) {
collector.emit(new Values(stock, vwap.getVwap(), vwap.getStartDate(), vwap.getEndDate()));
}
vwap = new Vwap(volume, price, date, date.plusSeconds(inteval));
stocks.put(stock, vwap);
collector.emit(input, new Values(stock, vwap.getVwap(), vwap.getStartDate(), vwap.getEndDate()));
}
collector.ack(input);
}
private boolean withinPeriod(Vwap vwap, DateTime quoteDate) {
if (vwap == null) return false;
DateTime vwapDate = vwap.getStartDate();
switch (period) {
case Periodicity.MINUTELY:
return ((dateOnlyComparator.compare(vwapDate, quoteDate) == 0)
&& vwapDate.getMinuteOfDay() == quoteDate.getMinuteOfDay());
case Periodicity.HOURLY:
return ((dateOnlyComparator.compare(vwapDate, quoteDate) == 0)
&& vwapDate.getHourOfDay() == quoteDate.getHourOfDay());
case Periodicity.DAILY:
return (dateOnlyComparator.compare(vwapDate, quoteDate) == 0);
case Periodicity.WEEKLY:
return (vwapDate.getYear() == quoteDate.getYear() &&
vwapDate.getWeekOfWeekyear() == quoteDate.getWeekOfWeekyear());
case Periodicity.MONTHLY:
return (vwapDate.getYear() == quoteDate.getYear() &&
vwapDate.getMonthOfYear() == quoteDate.getMonthOfYear());
}
return false;
}
public static final class Vwap {
private long totalShares = 0;
private double tradedValue = 0;
private double vwap = 0;
private DateTime startDate;
private DateTime endDate;
public Vwap(long shares, double price, DateTime start, DateTime end) {
this.startDate = start;
this.endDate = end;
update(shares, price, null);
}
public void update(long shares, double price, DateTime date) {
totalShares += shares;
tradedValue += (shares*price);
vwap = tradedValue/totalShares;
if (date != null) {
endDate = date;
}
}
public double getVwap() {
return vwap;
}
public DateTime getStartDate() {
return startDate;
}
public DateTime getEndDate() {
return endDate;
}
}
}