package org.cryptocoinpartners.module; import java.util.HashMap; import java.util.Map; import java.util.UUID; import javax.inject.Inject; import javax.inject.Singleton; import org.cryptocoinpartners.esper.annotation.When; import org.cryptocoinpartners.schema.Book; import org.cryptocoinpartners.schema.Market; import org.cryptocoinpartners.schema.Tick; import org.cryptocoinpartners.schema.Trade; import org.joda.time.Instant; import org.slf4j.Logger; /** * This class generates Ticks by listening for Trades and Books * * @author Tim Olson */ @SuppressWarnings("UnusedDeclaration") @Singleton public class TickWindow { @Inject private TickWindow(Context context) { this.context = context; accumulatingTickMap = new HashMap<>(); } // Every minute at five seconds after the minute @When("select current_timestamp() from pattern [every timer:at(*, *, *, *, *, 0)]") public void publishTick(long now) { for (AccumulatingTick accumulatingTick : accumulatingTickMap.values()) { Tick tick = accumulatingTick.flushTick(now); context.route(tick); log.trace("published tick " + tick); } } @When("select * from Trade") public void handleTrade(Trade t) { getAccumulatingTick(t.getMarket()).updateTrade(t); } @When("select * from Book") public void handleBook(Book b) { getAccumulatingTick(b.getMarket()).updateBook(b); } private AccumulatingTick getAccumulatingTick(Market ml) { AccumulatingTick at = accumulatingTickMap.get(ml.getId()); if (at == null) { at = new AccumulatingTick(ml); accumulatingTickMap.put(ml.getId(), at); } return at; } private static class AccumulatingTick extends Tick { private AccumulatingTick(Market ml) { super(ml, null, null, null, 0L, null); } @SuppressWarnings("ConstantConditions") private void updateTrade(Trade t) { setPriceCount(t.getPriceCount()); final Long oldVolume = getVolumeCount(); if (oldVolume == null) setVolumeCount(t.getVolumeCount()); else setVolumeCount(oldVolume + t.getVolumeCount()); } private void updateBook(Book b) { setLastBook(b); } private Tick flushTick(long now) { long startTime = getTime() == null ? now : getTime().getMillis(); final Instant endInstant = new Instant(now); final long volume = getVolumeCount() == null ? 0 : getVolumeCount(); Tick tick = new Tick(getMarket(), new Instant(startTime), endInstant, getPriceCount(), volume, getLastBook()); setStartInstant(endInstant); setVolumeCount(0L); return tick; } } @Inject private final Context context; @Inject private Logger log; private final Map<UUID, AccumulatingTick> accumulatingTickMap; }