package org.cryptocoinpartners.module;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Singleton;
import org.cryptocoinpartners.esper.annotation.When;
import org.cryptocoinpartners.schema.Book;
import org.cryptocoinpartners.schema.Exchanges;
import org.cryptocoinpartners.schema.Listing;
import org.cryptocoinpartners.schema.Market;
import org.cryptocoinpartners.schema.Offer;
import org.cryptocoinpartners.schema.Trade;
import org.cryptocoinpartners.service.QuoteService;
import org.cryptocoinpartners.util.ListingsMatrix;
import org.joda.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
/**
* This service listens to the Context and caches the most recent Trades and Books
*
* @author Tim Olson
*/
@SuppressWarnings("UnusedDeclaration")
@Singleton
public class BasicQuoteService implements QuoteService {
@Override
public Trade getLastTrade(Market market) {
return lastTradeByMarket.get(market.getSymbol());
}
@Override
public Trade getLastTrade(Listing listing) {
return lastTradeByListing.get(listing.getSymbol());
}
@Override
public Book getLastBook(Market market) {
return lastBookByMarket.get(market.getSymbol());
}
@Override
public Book getLastBook(Listing listing) {
return lastBookByListing.get(listing.getSymbol());
}
@Override
public Set<Market> getMarketsForListing(Listing listing) {
Set<Market> result = marketsByListing.get(listing.getSymbol());
return result == null ? Collections.<Market> emptySet() : result;
}
/**
* @return null if no Books for the given listing have been received yet
*/
@Override
public @Nullable
Offer getBestBidForListing(Listing listing) {
Offer bestBid = null;
for (Market market : marketsByListing.get(listing.getSymbol())) {
Book book = bestBidByMarket.get(market.getSymbol());
Offer testBestBid = book.getBestBid();
//noinspection ConstantConditions
if (bestBid == null || bestBid.getVolumeCount() == 0 || bestBid.getPriceCount() == 0
|| (testBestBid != null && testBestBid.getPrice().compareTo(bestBid.getPrice()) > 0))
bestBid = testBestBid;
}
bestBid = ((bestBid == null) ? getImpliedBestAskForListing(listing) : bestBid);
return bestBid;
}
@Override
public @Nullable
Offer getLastBidForMarket(Market market) {
Offer bestBid = null;
Offer testBestBid = null;
// for( Market market : marketsByListing.get(listing.getSymbol()) ) {
Book book = lastBookByMarket.get(market.getSymbol());
if (book != null)
testBestBid = book.getBestBid();
//noinspection ConstantConditions
if (bestBid == null || bestBid.getVolumeCount() == 0 || bestBid.getPriceCount() == 0
|| (testBestBid != null && testBestBid.getPrice().compareTo(bestBid.getPrice()) > 0))
bestBid = testBestBid;
return bestBid;
}
/**
* @return null if no Books for the given listing have been received yet
*/
@Override
public @Nullable
Offer getBestAskForListing(Listing listing) {
Offer bestAsk = null;
if (marketsByListing.get(listing.getSymbol()) != null) {
for (Market market : marketsByListing.get(listing.getSymbol())) {
Book book = bestAskByMarket.get(market.getSymbol());
Offer testBestAsk = book.getBestAsk();
//noinspection ConstantConditions
if (bestAsk == null || bestAsk.getVolumeCount() == 0 || bestAsk.getPriceCount() == 0
|| (testBestAsk != null && testBestAsk.getPrice().compareTo(bestAsk.getPrice()) < 0))
bestAsk = testBestAsk;
}
}
bestAsk = ((bestAsk == null) ? getImpliedBestAskForListing(listing) : bestAsk);
return bestAsk;
}
@Override
public @Nullable
Offer getImpliedBestAskForListing(Listing listing) {
try {
long bestImpliedAsk = impliedAskMatrix.getRate(listing.getBase(), listing.getQuote());
Market market = context.getInjector().getInstance(Market.class).findOrCreate(Exchanges.SELF, listing);
return new Offer(market, Instant.now(), Instant.now(), bestImpliedAsk, 0L);
} catch (java.lang.IllegalArgumentException e) {
return null;
}
}
@Override
public @Nullable
Offer getImpliedBestBidForListing(Listing listing) {
try {
long bestImpliedBid = impliedBidMatrix.getRate(listing.getBase(), listing.getQuote());
Market market = context.getInjector().getInstance(Market.class).findOrCreate(Exchanges.SELF, listing);
return new Offer(market, Instant.now(), Instant.now(), bestImpliedBid, 0L);
} catch (java.lang.IllegalArgumentException e) {
return null;
}
}
@Override
public @Nullable
Offer getLastAskForMarket(Market market) {
Offer bestAsk = null;
Offer testBestAsk = null;
Book book = lastBookByMarket.get(market.getSymbol());
if (book != null)
testBestAsk = book.getBestAsk();
//noinspection ConstantConditions
if (bestAsk == null || bestAsk.getVolumeCount() == 0 || bestAsk.getPriceCount() == 0
|| (testBestAsk != null && testBestAsk.getPrice().compareTo(bestAsk.getPrice()) < 0))
bestAsk = testBestAsk;
return bestAsk;
}
//@Priority(10)
@When("@Priority(10) select * from Book")
private void recordBook(Book b) {
Market market = b.getMarket();
handleMarket(market);
String listingSymbol = market.getListing().getSymbol();
Book lastBookForListing = lastBookByListing.get(listingSymbol);
if (lastBookForListing == null || lastBookForListing.getTime().isBefore(b.getTime()))
lastBookByListing.put(listingSymbol, b);
String marketSymbol = market.getSymbol();
Book lastBookForMarket = lastBookByMarket.get(marketSymbol);
if (lastBookForMarket == null || lastBookForMarket.getTime().isBefore(b.getTime()))
lastBookByMarket.put(marketSymbol, b);
Offer bestBid = b.getBestBid();
Book lastBestBidBook = bestBidByMarket.get(marketSymbol);
//noinspection ConstantConditions
if (bestBid != null && (lastBestBidBook == null || bestBid.getPrice().compareTo(lastBestBidBook.getBestBid().getPrice()) > 0))
bestBidByMarket.put(marketSymbol, b);
try {
impliedBidMatrix.updateRates(market.getBase(), market.getQuote(), b.getBidPrice().getCount());
} catch (java.lang.IllegalArgumentException e) {
try {
impliedBidMatrix.addAsset(market.getBase(), market.getQuote(), b.getBidPrice().getCount());
} catch (java.lang.IllegalArgumentException e2) {
// //we not recived enouhg trades to create a link to other currecny
// BigDecimal inverseRateBD = (((BigDecimal.valueOf(1 / (bestBid.getMarket().getQuote().getBasis()))).divide(
// BigDecimal.valueOf(bestBid.getPriceCount()), bestBid.getMarket().getBase().getScale(), RoundingMode.HALF_EVEN)).divide(BigDecimal
// .valueOf(bestBid.getMarket().getBase().getBasis())));
// long inverseCrossRate = inverseRateBD.longValue();
// impliedBidMatrix.addAsset(bestBid.getMarket().getQuote(), bestBid.getMarket().getBase(), inverseCrossRate);
}
}
Offer bestAsk = b.getBestAsk();
Book lastBestAskBook = bestAskByMarket.get(marketSymbol);
//noinspection ConstantConditions
if (bestAsk != null && (lastBestAskBook == null || bestAsk.getPrice().compareTo(lastBestAskBook.getBestAsk().getPrice()) < 0))
bestAskByMarket.put(marketSymbol, b);
try {
impliedAskMatrix.updateRates(market.getBase(), market.getQuote(), b.getAskPrice().getCount());
} catch (java.lang.IllegalArgumentException e) {
try {
impliedAskMatrix.addAsset(market.getBase(), market.getQuote(), b.getAskPrice().getCount());
} catch (java.lang.IllegalArgumentException e2) {
log.error("Threw a Execption, full stack trace follows:", e2);
e2.printStackTrace();
//we not recived enouhg trades to create a link to other currecny
//we not recived enouhg trades to create a link to other currecny
// BigDecimal inverseRateBD = (((BigDecimal.valueOf(1 / (bestAsk.getMarket().getQuote().getBasis()))).divide(
// BigDecimal.valueOf(bestAsk.getPriceCount()), bestAsk.getMarket().getBase().getScale(), RoundingMode.HALF_EVEN)).divide(BigDecimal
// .valueOf(bestAsk.getMarket().getBase().getBasis())));
// long inverseCrossRate = inverseRateBD.longValue();
// impliedBidMatrix.addAsset(bestAsk.getMarket().getQuote(), bestAsk.getMarket().getBase(), inverseCrossRate);
}
}
}
@When("@Priority(5) select * from Trade")
private void recordTrade(Trade t) {
Market market = t.getMarket();
handleMarket(market);
String listingSymbol = market.getListing().getSymbol();
Trade lastTradeForListing = lastTradeByListing.get(listingSymbol);
if (lastTradeForListing == null || lastTradeForListing.getTime().isBefore(t.getTime()))
lastTradeByListing.put(listingSymbol, t);
String marketSymbol = market.getSymbol();
Trade lastTradeForMarket = lastTradeByMarket.get(marketSymbol);
if (lastTradeForMarket == null || lastTradeForMarket.getTime().isBefore(t.getTime()))
lastTradeByMarket.put(marketSymbol, t);
}
private void handleMarket(Market market) {
final Listing listing = market.getListing();
final String listingSymbol = listing.getSymbol();
Set<Market> markets = marketsByListing.get(listingSymbol);
if (markets == null) {
markets = new HashSet<>();
markets.add(market);
marketsByListing.put(listingSymbol, markets);
} else
markets.add(market);
}
private final ListingsMatrix impliedBidMatrix = new ListingsMatrix();
private final ListingsMatrix impliedAskMatrix = new ListingsMatrix();
protected static Logger log = LoggerFactory.getLogger("org.cryptocoinpartners.quoteService");
@Inject
protected Context context;
private final Map<String, Trade> lastTradeByListing = new HashMap<>();
private final Map<String, Book> lastBookByListing = new HashMap<>();
private final Map<String, Trade> lastTradeByMarket = new HashMap<>();
private final Map<String, Book> lastBookByMarket = new HashMap<>();
private final Map<String, Book> bestBidByMarket = new HashMap<>();
private final Map<String, Book> bestAskByMarket = new HashMap<>();
private final Map<String, Set<Market>> marketsByListing = new HashMap<>();
}