/
Java TCP Handler for CME MDP 3.0 Conflated Feed

Java TCP Handler for CME MDP 3.0 Conflated Feed

Introduction

This document introduces the Java TCP Handler, a component specifically engineered to interface with the conflated market data feed of the CME Market Data Platform (MDP 3.0). Designed to capitalize on the efficiency of this feed, the handler ensures low-latency delivery of market updates.

The CME Globex MDP 3.0 platform utilizes a conflated feed, meaning only the most recent market data updates for each instrument are transmitted. This approach significantly reduces bandwidth consumption and processing overhead, allowing for faster and more efficient data handling. The Java TCP Handler fully supports the features of this platform, effectively feeding real-time, conflated CME market data directly into your client application with microsecond-level latency.

About CME MDP 3.0 Conflated Feed

The CME MDP 3.0 platform offers a "conflated" TCP market data feed. Conflation, in this context, means that if multiple updates for the same market instrument occur within a short period, only the latest update is sent to the client application. This approach offers several key advantages:

  • Reduced Bandwidth Consumption: By transmitting only the most recent information, the conflated feed significantly reduces the amount of network bandwidth required. This is particularly beneficial for applications operating in environments with limited network capacity or when monitoring a large number of instruments.

  • Lower Processing Overhead: Client applications receiving a conflated feed experience lower processing loads. They only need to process the latest state of the market, rather than dealing with a high volume of intermediate updates that might be quickly superseded.

  • Focus on the Current Market State: For many trading and analytical applications, the most crucial piece of information is the current state of the market. The conflated feed ensures that applications always have the most up-to-date view without needing to process historical ticks within a short timeframe.

  • Improved Stability in High-Volume Periods: During periods of intense market activity, the number of raw market data updates can be extremely high. Conflation helps to smooth out these bursts of data, making the feed more manageable and stable for client applications.

  • Cost Efficiency: Lower bandwidth consumption can translate to reduced costs associated with network infrastructure and data processing, especially for high-frequency trading operations or large-scale data consumers.

In essence, the CME MDP 3.0 conflated TCP feed is optimized for efficiency. It prioritizes delivering the most current market information while minimizing the resources needed to transmit and process that data. This makes it an ideal choice for applications that require a near real-time understanding of the market without needing every single price tick.

Code Examples

package com.example; import com.epmbfix.mdpconflatedtcp.impl.cme.CMEConnection; import com.epmbfix.mdpconflatedtcp.impl.transport.TcpTransport; import com.epmbfix.mdpconflatedtcp.interfaces.*; import mdpsessionmgmt.RequestAck206Decoder; import mdpsessionmgmt.SubscriptionReqType; import mktdata.SnapshotFullRefresh38Decoder; public class Main { public static void main(String[] args) throws Exception { Transport transport = new TcpTransport("127.0.0.1", 55506); CMEConnection connection = CMEConnection .builder() .setFirm(Settings.FIRM) .setAccessKeyId(Settings.ACCESS_ID) .setSessionId(Settings.SESSION_ID) .setSessionSignatureKey(Settings.KEY) .setTransport(transport) .build(); MDPSession mdpSession = connection.createSession(); mdpSession.addSessionListener(new SessionListener() { @Override public void onMessage(MDPIncomingMessage message, MDPSession session) { if (message.getMessage() instanceof RequestAck206Decoder) { // DO SOMETHING HERE } else if (message.getMessage() instanceof SnapshotFullRefresh38Decoder) { SnapshotFullRefresh38Decoder snapshot = (SnapshotFullRefresh38Decoder) message.getMessage(); snapshot.lowLimitPrice().mantissa(); // DO SOMETHING HERE } } @Override public void onSessionStatusChanged(MDPSessionState state, MDPSession session) { switch (state) { case CREATED : System.out.println("Session created"); break; case ESTABLISHED: System.out.println("Session established"); try { session.securityListRequest(1, SubscriptionReqType.Snapshot, null, null); session.securityStatusRequest(1, SubscriptionReqType.Snapshot, null, null); session.marketDataRequest(1, SubscriptionReqType.Snapshot, null, null); } catch (Exception e) { e.printStackTrace(); } break; default : // do something with default break; } System.out.println("MDP Message status received"); } }); mdpSession.connect().block(); System.out.println("GoodBye!"); } }

How to build

This project utilizes Maven for building. To compile and package the application, execute the following command in your terminal:

mvn clean install

To generate the necessary Java encoder and decoder classes from the CME message templates, run the following Maven command:

mvn exec:exec

These generated classes are essential for the application to understand and process the market data messages from CME.

Sample application

This sample application provides a command-line interface to test the TCP client and its connection to the CME MDP server. You can start the application using the following command:

java -jar cme-mdp-conflated-tcp-1.0-jar-with-dependencies.jar <channel_id> <channel_settings_file>

Where:

  1. <channel_id> represents the identifier of the channel configuration you want to use. This ID corresponds to an entry in the channel-settings.properties file.

  2. <channel_settings_file> is the path to the property file containing the connection settings required to establish a connection with CME.

The channel-settings.properties file should be formatted as follows:

channels=51,517 channel.51.host=127.0.0.1 channel.51.port=55506 channel.51.sessionId=SESS2 channel.51.key=C_dE0vUUVpvR6r56Ee5fniujnpya9gE7cX-tOPsqZtM channel.51.accessKeyId=<your security key> channel.51.firm=FIRM1 channel.517.host=69.50.113.11 channel.517.port=9053 channel.517.sessionId=SESS2 channel.517.key=<your security key> channel.517.accessKeyId=99Ygw5JTW2P2v2xWDOPN channel.517.firm=FIRM2

After successfully starting the application, you will see the following menu:

1. Subscribe to security lists by SecurityGroup 2. Subscribe to security lists by SecurityID 3. Subscribe to security status by SecurityGroup 4. Subscribe to security status by SecurityID 5. Subscribe to MD by SecurityGroup 6. Subscribe to MD by SecurityID MDP Message status received: TERMINATED Session established

You can choose any of the listed options by entering the corresponding number. This will initiate the process of sending a subscription request to CME. Following your selection, another menu will appear asking for the subscription type:

Choose subscription type 1. Snapshot 2. SnapshotAndUpdates 3. Unsubscribe

For options involving SecurityGroup, the application will prompt you to enter comma-separated security group values (e.g., FRTD,DFTR,FGDRT,...). Each group name is limited to a maximum of 6 characters. If any entered group name exceeds this limit, the subscription request will not be sent. You can specify up to 254 security groups in a single request. Entering nothing will send a subscription request for all available security groups.

For options involving SecurityID, you will be asked to input comma-separated numeric security IDs (e.g., 74641523,74637936,74662010,74660473). The same limitations apply as with security groups: a maximum of 254 IDs per request. Any non-numeric input will be ignored. Leaving the input empty will trigger a subscription request for all security groups and IDs.

Decoding solution

The process of parsing and decoding incoming market data messages relies on Java classes that are automatically generated from CME's message templates. These generated classes are included within the project and can be found in the mktdata and mdpsessionmgmt packages.

The DecoderImpl class is responsible for implementing the decoding logic. During its initialization, this class scans the aforementioned packages to identify all classes related to decoding. It then utilizes these classes to interpret the raw market data received from CME.

TCP Connection

The underlying TCP connection to the server is managed by the AutoReconnectTcpClient class. This class is designed to automatically attempt to re-establish the connection every 0.5 seconds if the connection is lost, ensuring a resilient and continuous data feed.

Messages samples

Here are some examples of the different types of messages you might encounter:

(sbeTemplateId=208|sbeSchemaId=2|sbeSchemaVersion=0|sbeBlockLength=5):mDReqID=201|subscriptionReqType=Snapshot|noSecurityGroups=[]|noRelatedSym=[]
(sbeTemplateId=58|sbeSchemaId=1|sbeSchemaVersion=13|sbeBlockLength=276):matchEventIndicator={}|totNumReports=4294967295|securityUpdateAction=Add|lastUpdateTime=1733870629443112505|mDSecurityTradingStatus=NULL_VAL|applID=517|marketSegmentID=46|underlyingProduct=13|securityExchange=BTAM|securityGroup=EUSA|asset=ITDUSA|symbol=ITDUSA:Q56UL7ENEZCB|securityID=72838328|securityType=REPO|cFICode=LRSTXD|currency=EUR|settlCurrency=|matchAlgorithm=70|minTradeVol=1|maxTradeVol=9999|minPriceIncrement=(mantissa=5000000|)|displayFactor=(mantissa=1000000000|)|unitOfMeasure=EUR|unitOfMeasureQty=(mantissa=1000000000000000|)|tradingReferencePrice=(mantissa=9223372036854775807|)|tradingReferenceDate=65535|highLimitPrice=(mantissa=10000000000|)|lowLimitPrice=(mantissa=-10000000000|)|maxPriceVariation=(mantissa=9223372036854775807|)|financialInstrumentFullName=SA_BTPS_3.85_12/29|partyRoleClearingOrg=MONTE|startDate=20070|endDate=20252|terminationType=S-6M|securitySubType=Special|moneyOrPar=Par|maxNoOfSubstitutions=0|priceQuoteMethod=RATE|userDefinedInstrument=78|riskSet=|marketSet=EUSA|instrumentGUID=610189782388204609|termCode=S-6M|brokenDateTermType=255|noEvents=[(eventType=Activation|eventTime=1733871600000000000),(eventType=LastEligibleTradeDate|eventTime=1733956200000000000)]|noMDFeedTypes=[(mDFeedType=GBX|marketDepth=10)]|noInstAttrib=[(instAttribValue={negativePriceOutrightEligible,zeroPriceOutrightEligible,invertedBook})]|noLotTypeRules=[(lotType=2|minLotSize=(mantissa=10000|)),(lotType=5|minLotSize=(mantissa=10000|))]|noUnderlyings=[(underlyingSymbol=ITBOND 3.85 151229|underlyingSecurityID=29046993|underlyingSecurityAltID=IT0005519787|underlyingSecurityAltIDSource=ISIN|underlyingFinancialInstrumentFullName=BTPS_3.85_12/29|underlyingSecurityType=EUSOV|underlyingCountryOfIssue=IT|underlyingIssuer=815600DE60799F5A9309|underlyingMaxLifeTime=255|underlyingMinDaysToMaturity=65535|underlyingInstrumentGUID=199248732661098374|underlyingMaturityDate=21898)]|noRelatedInstruments=[(relatedSecurityID=72832370|relatedSymbol=ITDUSA:KZOGANWQEUUD|relatedInstrumentGUID=388934660853486211)]|noBrokenDates=[]
(sbeTemplateId=209|sbeSchemaId=2|sbeSchemaVersion=0|sbeBlockLength=5):mDReqID=301|subscriptionReqType=SnapshotAndUpdates|noSecurityGroups=[]|noRelatedSym=[]
(sbeTemplateId=30|sbeSchemaId=1|sbeSchemaVersion=13|sbeBlockLength=30):transactTime=1733875200000000000|securityGroup=EUBL|asset=|securityID=2147483647|tradeDate=20068|matchEventIndicator={}|securityTradingStatus=ReadyToTrade|haltReason=GroupSchedule|securityTradingEvent=ResetStatistics
(sbeTemplateId=205|sbeSchemaId=2|sbeSchemaVersion=0|sbeBlockLength=5):mDReqID=501|subscriptionReqType=SnapshotAndUpdates|noSecurityGroups=[]|noRelatedSym=[]
(sbeTemplateId=59|sbeSchemaId=1|sbeSchemaVersion=13|sbeBlockLength=13):transactTime=1733898835248994125|matchEventIndicator={}|securityID=72807554|noMDEntries=[(orderID=46183248911|mDOrderPriority=2259740|mDEntryPx=(mantissa=3820000000|)|mDDisplayQty=47|mDEntryType=Bid),(orderID=46183248912|mDOrderPriority=2259750|mDEntryPx=(mantissa=3490000000|)|mDDisplayQty=47|mDEntryType=Offer)]
(sbeTemplateId=61|sbeSchemaId=1|sbeSchemaVersion=13|sbeBlockLength=37):transactTime=1733904665838706595|matchEventIndicator={}|securityID=72836463|highLimitPrice=(mantissa=10000000000|)|lowLimitPrice=(mantissa=-10000000000|)|maxPriceVariation=(mantissa=9223372036854775807|)|noMDEntries=[(mDEntryPx=(mantissa=3750000000|)|mDEntrySize=40|tradeableSize=40|numberOfOrders=1|mDPriceLevel=1|openCloseSettlFlag=NULL_VAL|mDEntryType=Bid|tradingReferenceDate=65535|settlPriceType={nullValue}),(mDEntryPx=(mantissa=3000000000|)|mDEntrySize=40|tradeableSize=40|numberOfOrders=1|mDPriceLevel=1|openCloseSettlFlag=NULL_VAL|mDEntryType=Offer|tradingReferenceDate=65535|settlPriceType={nullValue})]
(sbeTemplateId=46|sbeSchemaId=1|sbeSchemaVersion=13|sbeBlockLength=11):transactTime=1733908700010438865|matchEventIndicator={lastQuoteMsg,endOfEvent}|noMDEntries=[(mDEntryPx=(mantissa=-520000000|)|mDEntrySize=56|securityID=72826480|rptSeq=0|numberOfOrders=1|mDPriceLevel=1|mDUpdateAction=New|mDEntryType=Bid|tradeableSize=56)]|noOrderIDEntries=[]
(sbeTemplateId=62|sbeSchemaId=1|sbeSchemaVersion=13|sbeBlockLength=11):transactTime=1734000704828303317|matchEventIndicator={endOfEvent}|noMDEntries=[(underlyingSecurityAltID=SE0004517290|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=101774000000|)|dirtyPrice=(mantissa=102970000000|)|underlyingInstrumentGUID=1112585263956509266|mDStreamID=Refinitiv),(underlyingSecurityAltID=SE0011281922|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=94819000000|)|dirtyPrice=(mantissa=94880000000|)|underlyingInstrumentGUID=403745928055549564|mDStreamID=Refinitiv),(underlyingSecurityAltID=SE0013935319|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=89188000000|)|dirtyPrice=(mantissa=89260000000|)|underlyingInstrumentGUID=510258081007226863|mDStreamID=Refinitiv),(underlyingSecurityAltID=SE0009496367|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=96434000000|)|dirtyPrice=(mantissa=96870000000|)|underlyingInstrumentGUID=77179074447331612|mDStreamID=Refinitiv),(underlyingSecurityAltID=SE0021308541|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=101526500000|)|dirtyPrice=(mantissa=102850000000|)|underlyingInstrumentGUID=920616380202546857|mDStreamID=Refinitiv),(underlyingSecurityAltID=JP1300441E92|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=97785500000|)|dirtyPrice=(mantissa=98170000000|)|underlyingInstrumentGUID=305219191088852681|mDStreamID=Refinitiv),(underlyingSecurityAltID=JP14000117B7|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=107615500000|)|dirtyPrice=(mantissa=108160000000|)|underlyingInstrumentGUID=40383390705711624|mDStreamID=Refinitiv),(underlyingSecurityAltID=JP1300431E60|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=98087500000|)|dirtyPrice=(mantissa=98900000000|)|underlyingInstrumentGUID=840521072018095964|mDStreamID=Refinitiv),(underlyingSecurityAltID=JP1300491FC9|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=91350500000|)|dirtyPrice=(mantissa=92020000000|)|underlyingInstrumentGUID=650973998771015609|mDStreamID=Refinitiv),(underlyingSecurityAltID=JP1300471F60|underlyingSecurityAltIDSource=ISIN|collateralMarketPrice=(mantissa=95317500000|)|dirtyPrice=(mantissa=96080000000|)|underlyingInstrumentGUID=351501009828417156|mDStreamID=Refinitiv)]

Related content