org.openfeed.client.examples.OpenfeedClientHandlerImpl Maven / Gradle / Ivy
The newest version!
package org.openfeed.client.examples;
import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.openfeed.*;
import org.openfeed.Trades.Entry;
import org.openfeed.client.api.impl.ConnectionStats;
import org.openfeed.client.api.impl.MessageStats;
import org.openfeed.client.api.impl.MessageStats.StatType;
import org.openfeed.client.api.*;
import org.openfeed.client.api.impl.OpenfeedClientConfigImpl;
import org.openfeed.client.api.impl.PbUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.channel.ChannelPromise;
public class OpenfeedClientHandlerImpl implements OpenfeedClientHandler {
private static final Logger log = LoggerFactory.getLogger(OpenfeedClientHandler.class);
private OpenfeedClientConfig config;
private InstrumentCache instrumentCache;
private ConnectionStats connectionStats;
private MarketsManager marketsManager;
private int awaitingNumDefinitions;
private ChannelPromise instrumentDownloadPromise;
private int numDefinitions;
public OpenfeedClientHandlerImpl(OpenfeedClientConfig config, InstrumentCache instrumentCache,
ConnectionStats stats, MarketsManager marketsManager) {
this.config = config;
this.instrumentCache = instrumentCache;
this.connectionStats = stats;
this.marketsManager = marketsManager;
}
public OpenfeedClientHandlerImpl(OpenfeedClientConfigImpl config, InstrumentCache instrumentCache, MarketsManager marketsManager) {
this(config, instrumentCache, new ConnectionStats(), marketsManager);
}
@Override
public void onLoginResponse(LoginResponse loginResponse) {
log.info("{}: < LoginResponse {}", config.getClientId(), PbUtil.toJson(loginResponse));
}
@Override
public void onLogoutResponse(LogoutResponse logoutResponse) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(logoutResponse));
}
@Override
public void onInstrumentResponse(InstrumentResponse instrumentResponse) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(instrumentResponse));
awaitingNumDefinitions = instrumentResponse.getNumberOfDefinitions();
numDefinitions = 0;
}
@Override
public void onInstrumentReferenceResponse(InstrumentReferenceResponse instrumentReferenceResponse) {
log.debug("{}: < {}", config.getClientId(), PbUtil.toJson(instrumentReferenceResponse));
log.info("{}/{}/{} ofExc: {} ddf: {} ddfExc: {} ddfBaseCode: {}", instrumentReferenceResponse.getSymbol(), instrumentReferenceResponse.getChannelId(), instrumentReferenceResponse.getMarketId(),
instrumentReferenceResponse.getExchange(), instrumentReferenceResponse.getDdfSymbol(), instrumentReferenceResponse.getDdfExchange(),
instrumentReferenceResponse.getDdfBaseCode()
);
}
@Override
public void onSubscriptionResponse(SubscriptionResponse subscriptionResponse) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(subscriptionResponse));
if (subscriptionResponse.getStatus().getResult() != Result.SUCCESS) {
log.error("{}: Subscription Failed {}", config.getClientId(), PbUtil.toJson(subscriptionResponse));
}
}
@Override
public void onMarketStatus(MarketStatus marketStatus) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(marketStatus));
}
@Override
public void onHeartBeat(HeartBeat hb) {
if (config.isLogHeartBeat()) {
log.info("{}: {} < {}", config.getClientId(), hb.getExchange() ? "Exchange" : "", PbUtil.toJson(hb));
}
connectionStats.getMessageStats().incrHeartBeats();
}
@Override
public void onInstrumentDefinition(InstrumentDefinition definition) {
if (config.isLogInstrument()) {
log.info("INSTRUMENT {}: < {}", config.getClientId(), PbUtil.toJson(definition));
}
connectionStats.getMessageStats().incrInstruments();
this.instrumentCache.addInstrument(definition);
this.numDefinitions++;
if (this.awaitingNumDefinitions == numDefinitions) {
log.info("Finished instrument download of {} instruments", this.awaitingNumDefinitions);
this.awaitingNumDefinitions = this.numDefinitions = 0;
if (instrumentDownloadPromise != null) {
instrumentDownloadPromise.setSuccess();
}
}
updateExchangeStats(definition.getMarketId(), StatType.instrument);
marketsManager.createMarket(definition);
}
@Override
public void onMarketSnapshot(MarketSnapshot snapshot) {
if (config.isLogSnapshot()) {
log.info("SNAPSHOT {}: < {}", config.getClientId(), PbUtil.toJson(snapshot));
}
connectionStats.getMessageStats().incrSnapshots();
updateExchangeStats(snapshot.getMarketId(), StatType.snapshot);
Optional market = marketsManager.getMarket(snapshot.getMarketId());
if (market.isPresent()) {
market.get().apply(snapshot);
if (config.isLogDepth()) {
if (config.isLogDepth()) {
log.info("SNAPSHOT DEPTH:\n{}", market.get().getDepthPriceLevel());
}
}
}
}
@Override
public void onMarketUpdate(MarketUpdate update) {
connectionStats.getMessageStats().incrUpdates();
updateExchangeStats(update.getMarketId(), StatType.update);
//
InstrumentDefinition definition = instrumentCache.getInstrument(update.getMarketId());
// Symbol is optional
String symbol = null;
if (update.getSymbol() != null) {
symbol = update.getSymbol();
} else {
symbol = definition.getSymbol();
}
if (config.isLogUpdate()) {
log.info("UPDATE: {}: {}: < {}", config.getClientId(), symbol, PbUtil.toJson(update));
}
Optional market = marketsManager.getMarket(update.getMarketId());
if (market.isPresent()) {
market.get().apply(update);
if (config.isLogDepth()) {
log.info("{}", market.get().getDepthPriceLevel());
}
}
switch (update.getDataCase()) {
case BBO:
BestBidOffer bbo = update.getBbo();
if (bbo.getRegional()) {
// Regional/Participant Quote
connectionStats.getMessageStats().incrBbo();
updateExchangeStats(update.getMarketId(), StatType.bbo);
} else {
// NBBO for Equities
connectionStats.getMessageStats().incrNBbo();
updateExchangeStats(update.getMarketId(), StatType.nbbo);
}
if (config.isLogBbo()) {
log.info("{}: {}: < {}", config.getClientId(), symbol, PbUtil.toJson(update));
}
break;
case CAPITALDISTRIBUTIONS:
break;
case CLEARBOOK:
break;
case CLOSE:
break;
case DATA_NOT_SET:
break;
case DEPTHORDER:
connectionStats.getMessageStats().incrDepthOrder();
updateExchangeStats(update.getMarketId(), StatType.depth_order);
break;
case DEPTHPRICELEVEL:
connectionStats.getMessageStats().incrDepthPrice();
updateExchangeStats(update.getMarketId(), StatType.depth_price);
break;
case DIVIDENDSINCOMEDISTRIBUTIONS:
break;
case HIGH:
break;
case INDEX:
break;
case INSTRUMENTSTATUS:
break;
case LAST:
break;
case LOW:
break;
case MARKETSUMMARY:
connectionStats.getMessageStats().incrMarketSummary();
updateExchangeStats(update.getMarketId(), StatType.marketSummary);
break;
case MONETARYVALUE:
break;
case NETASSETVALUE:
break;
case NEWS:
break;
case NUMBEROFTRADES:
break;
case OPEN:
break;
case OPENINTEREST:
break;
case PREVCLOSE:
break;
case SETTLEMENT:
connectionStats.getMessageStats().incrSettlements();
updateExchangeStats(update.getMarketId(), StatType.settlement);
break;
case SHARESOUTSTANDING:
break;
case TRADES:
Trades trades = update.getTrades();
for (Entry te : trades.getTradesList()) {
switch (te.getDataCase()) {
case TRADE:
connectionStats.getMessageStats().incrTrades();
updateExchangeStats(update.getMarketId(), StatType.trade);
Trade trade = te.getTrade();
String tradeId = trade.getTradeId().toStringUtf8();
if (config.isLogTrade()) {
log.info("{}: {}/{}/{}: Trade tradeId: {} < {}", config.getClientId(), symbol,
update.getMarketId(), definition.getChannel(), tradeId, PbUtil.toJson(update));
}
break;
case TRADECANCEL:
connectionStats.getMessageStats().incrTradeCancel();
updateExchangeStats(update.getMarketId(), StatType.trade_cancel);
TradeCancel cancel = te.getTradeCancel();
tradeId = cancel.getTradeId().toStringUtf8();
if (config.isLogTradeCancel()) {
log.info("{}: {}/{}/{}: Cancel tradeId: {} < {}", config.getClientId(), symbol,
update.getMarketId(), definition.getChannel(), tradeId, PbUtil.toJson(update));
}
break;
case TRADECORRECTION:
connectionStats.getMessageStats().incrTradeCorrection();
updateExchangeStats(update.getMarketId(), StatType.trade_correction);
TradeCorrection correction = te.getTradeCorrection();
tradeId = correction.getTradeId().toStringUtf8();
if (config.isLogTradeCorrection()) {
log.info("{}: {}/{}/{}: Correction tradeId: {} < {}", config.getClientId(), symbol,
update.getMarketId(), definition.getChannel(), tradeId, PbUtil.toJson(update));
}
break;
default:
case DATA_NOT_SET:
break;
}
}
break;
case VOLUME:
break;
case VWAP:
break;
case YEARHIGH:
break;
case YEARLOW:
break;
default:
break;
}
}
@Override
public void onVolumeAtPrice(VolumeAtPrice cumulativeVolume) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(cumulativeVolume));
}
@Override
public void onOhlc(Ohlc ohlc) {
connectionStats.getMessageStats().incrOHLC();
updateExchangeStats(ohlc.getMarketId(), StatType.ohlc);
if (config.isLogOhlc()) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(ohlc));
}
}
@Override
public void onInstrumentAction(InstrumentAction instrumentAction) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(instrumentAction));
}
@Override
public void onListSubscriptionsResponse(ListSubscriptionsResponse listSubscriptionsResponse) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(listSubscriptionsResponse));
}
private long getNowNs() {
Instant now = Instant.now();
return TimeUnit.SECONDS.toNanos(now.getEpochSecond()) + now.getNano();
}
private void updateExchangeStats(long marketId, MessageStats.StatType type) {
InstrumentDefinition def = instrumentCache.getInstrument(marketId);
if (def != null) {
MessageStats stats = connectionStats.getExchangeMessageStats(def.getChannel(), def.getExchangeCode());
switch (type) {
case instrument:
stats.incrInstruments();
break;
case bbo:
stats.incrBbo();
break;
case nbbo:
stats.incrNBbo();
break;
case snapshot:
stats.incrSnapshots();
break;
case trade:
stats.incrTrades();
break;
case trade_correction:
stats.incrTradeCorrection();
break;
case trade_cancel:
stats.incrTradeCancel();
break;
case update:
stats.incrUpdates();
break;
case ohlc:
stats.incrOHLC();
break;
case depth_price:
stats.incrDepthPrice();
break;
case depth_order:
stats.incrDepthOrder();
break;
case settlement:
stats.incrSettlements();
break;
case marketSummary:
stats.incrMarketSummary();
break;
default:
break;
}
}
}
@Override
public void setInstrumentPromise(ChannelPromise promise) {
this.instrumentDownloadPromise = promise;
}
@Override
public void onExchangeResponse(ExchangeResponse exchangeResponse) {
log.info("{}: < {}", config.getClientId(), PbUtil.toJson(exchangeResponse));
}
@Override
public ConnectionStats getConnectionStats() {
return this.connectionStats;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy