in java/runner/src/intTest/java/com/epam/deltix/data/connectors/validator/L1DataValidator.java [146:255]
public void sendPackage(PackageHeaderInfo headerInfo) {
if ((!headerInfo.hasSymbol()) || (!CharSequenceUtils.equals(headerInfo.getSymbol(), symbol))) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Incorrect symbol", Severity.ERROR);
}
if (!headerInfo.hasEntries()) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Missed entries list", Severity.ERROR);
}
if (!headerInfo.hasPackageType()) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Missed package type", Severity.ERROR);
}
if (headerInfo.getEntries().size() == 0) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Empty entries list", Severity.WARNING);
}
if (headerInfo.getPackageType() == PackageType.VENDOR_SNAPSHOT) {
long exchangeId = headerInfo.getEntries().get(0).getExchangeId();
for (int i = 0; i < headerInfo.getEntries().size(); ++i) {
if (headerInfo.getEntries().get(i).getExchangeId() != exchangeId) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "We support only one exchangeId for snapshots", Severity.ERROR);
}
}
DecimalLongDecimalLongPair askPair = bestAskDictionary.get(exchangeId, null);
DecimalLongDecimalLongPair bidPair = bestBidDictionary.get(exchangeId, null);
if (askPair != null) {
askPair.setFirst(Decimal64Utils.POSITIVE_INFINITY);
bidPair.setFirst(Decimal64Utils.NEGATIVE_INFINITY);
askPair.setSecond(Decimal64Utils.ZERO);
bidPair.setSecond(Decimal64Utils.ZERO);
}
}
else if (headerInfo.getPackageType() == PackageType.PERIODICAL_SNAPSHOT) {
checkPeriodicalSnapshotState(headerInfo);
}
exchangeIds.clear();
previousBestBids.clear();
previousBestAsks.clear();
for (int i = 0; i < headerInfo.getEntries().size(); ++i) {
if (headerInfo.getEntries().get(i) instanceof L1Entry) {
L1Entry l1Entry = (L1Entry)headerInfo.getEntries().get(i);
validateEntry(headerInfo, l1Entry);
if (!l1Entry.hasSize()) continue;
long exchangeId = l1Entry.getExchangeId();
if (bestAskDictionary.get(exchangeId, null) == null) {
bestAskDictionary.put(exchangeId, new DecimalLongDecimalLongPair(Decimal64Utils.POSITIVE_INFINITY, Decimal64Utils.ZERO));
bestBidDictionary.put(exchangeId, new DecimalLongDecimalLongPair(Decimal64Utils.POSITIVE_INFINITY, Decimal64Utils.ZERO));
}
DecimalLongDecimalLongPair askPair = bestAskDictionary.get(exchangeId, null);
DecimalLongDecimalLongPair bidPair = bestBidDictionary.get(exchangeId, null);
if (!exchangeIds.contains(exchangeId)) {
exchangeIds.add(exchangeId);
previousBestAsks.add(askPair.getFirst());
previousBestBids.add(bidPair.getFirst());
}
if ((!l1Entry.hasPrice()) || (!l1Entry.hasSize())) continue;
if (l1Entry.getSide() == QuoteSide.ASK) {
askPair.setFirst(l1Entry.getPrice());
askPair.setSecond(l1Entry.getSize());
} else {
bidPair.setFirst(l1Entry.getPrice());
bidPair.setSecond(l1Entry.getSize());
}
} else if (headerInfo.getEntries().get(i) instanceof TradeEntry) {
TradeEntry tradeEntry = (TradeEntry)headerInfo.getEntries().get(i);
validateEntry(headerInfo, tradeEntry);
}
}
long minAsk = Decimal64Utils.POSITIVE_INFINITY;
long maxAsk = Decimal64Utils.NEGATIVE_INFINITY;
long minBid = Decimal64Utils.POSITIVE_INFINITY;
long maxBid = Decimal64Utils.NEGATIVE_INFINITY;
for (int i = 0; i < exchangeIds.size(); ++i) {
DecimalLongDecimalLongPair askPair = bestAskDictionary.get(exchangeIds.get(i), null);
DecimalLongDecimalLongPair bidPair = bestBidDictionary.get(exchangeIds.get(i), null);
if (!Decimal64Utils.isInfinity(bidPair.getFirst()) && !Decimal64Utils.isInfinity(askPair.getFirst()) && Decimal64Utils.isGreater(bidPair.getFirst(), askPair.getFirst()) && checkBidMoreThanAsk) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Bid > Ask", Severity.WARNING);
}
if (!Decimal64Utils.isInfinity(askPair.getFirst())) {
minAsk = Decimal64Utils.min(minAsk, askPair.getFirst());
maxAsk = Decimal64Utils.max(maxAsk, askPair.getFirst());
}
if (!Decimal64Utils.isInfinity(bidPair.getFirst())) {
minBid = Decimal64Utils.min(minBid, bidPair.getFirst());
maxBid = Decimal64Utils.max(maxBid, bidPair.getFirst());
}
if (checkPackageMisPrice) {
if (!Decimal64Utils.isInfinity(previousBestAsks.get(i)) && !Decimal64Utils.isZero(previousBestAsks.get(i)) && (!Decimal64Utils.isInfinity(askPair.getFirst()))) {
if (Decimal64Utils.isGreater(Decimal64Utils.abs(Decimal64Utils.divide(Decimal64Utils.subtract(previousBestAsks.get(i), askPair.getFirst()), previousBestAsks.get(i))), packageMisPrice)) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Too big price change after this package", Severity.WARNING);
}
}
if (!Decimal64Utils.isInfinity(previousBestBids.get(i)) && !Decimal64Utils.isZero(previousBestBids.get(i)) && (!Decimal64Utils.isInfinity(bidPair.getFirst()))) {
if (Decimal64Utils.isGreater(Decimal64Utils.abs(Decimal64Utils.divide(Decimal64Utils.subtract(previousBestBids.get(i), bidPair.getFirst()), previousBestBids.get(i))), packageMisPrice)) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Too big price change after this package", Severity.WARNING);
}
}
}
}
if (checkExchangeMisPrice) {
if (!Decimal64Utils.isZero(minAsk) && Decimal64Utils.isGreater(Decimal64Utils.divide(Decimal64Utils.subtract(maxAsk, minAsk), Decimal64Utils.abs(minAsk)), exchangeMisPrice)) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Ask Mispricing between exchanges", Severity.WARNING);
}
if (!Decimal64Utils.isZero(minBid) && Decimal64Utils.isGreater(Decimal64Utils.divide(Decimal64Utils.subtract(maxBid, minBid), Decimal64Utils.abs(minBid)), exchangeMisPrice)) {
sendMessageToLogger(headerInfo, TypeConstants.EXCHANGE_NULL, "Bid Mispricing between exchanges", Severity.WARNING);
}
}
}