Onix Solutions Logo

ICE iMpact Multicast Price Feed Handler — Programming Guide

Version 1.60.0

TOC

Introduction

The Onix Solutions Java ICE iMpact Multicast Price Feed Handler (JIFH) is a Java library that provides an access to the ICE iMpact market data using multicast feed protocol. The JIFH exposes a high-level Java API that enables developers to efficiently build and maintain applications without expending time and effort supporting the raw low level API protocol.

Below are the key features of the ICE iMpact Market Data Feed Handler (JIFH):

Note
To fully comprehend the core concepts of the ICE iMpact Market Data System, we recommend reading the "ICE iMpact Multicast Feed Technical Specification" documentation prior to continuing with this guide. We also recommend viewing the source code of the sample project included within the software distribution package provided.

System Requirements

Java

Supported Java version is 1.8.*.

JDK

The list of compatible JDKs:

Getting Started

Prerequisites

The Handler needs credentials from ICE to login and download product definitions. Please contact ICE Support to get a username and password for TCP connection. When you receive it please update the connectivity configuration file with these values.

Quick Start

For those who are unfamiliar with the JIFH we recommend that you take the following actions in priority sequence:

Licensing

The JIFH needs a valid license for successful execution. If the licensing subsystem is not able to find a valid license, it throws an exception. Also, a license is verified each time an attempt to start market data processing is done.

The biz.onixs.ice.impact.handler.HandlerOptions class exposes the setLicenseDir() method which must be used to instruct the JIFH where to look for a valid license. By default, the licensing services look for a license in the current directory of the application. However, by using noted method, it is possible to specify another directory anywhere on file system.

The licensing subsystem looks for a valid license in the specified directory and selects the best one. If multiple licenses are available, it selects the most significant one (for example, a production license is selected instead of a trial one if both are available).

The following example demonstrates how to perform initialization of the JIFH:

String connectivityConfiguration = "ConnectivityConfiguration.AP1.xml";
String networkInterface = "127.0.0.1";
String licenseDir = "../../license";

HandlerOptions handlerOptions = new HandlerOptions(connectivityConfiguration, networkInterface, licenseDir);
Handler handler = new Handler(handlerOptions);

Logging

By default, the JIFH logs all aspects of its activity whilst processing market data. The SLF4J (Simple Logging Facade for Java) is used internally by the JIFH. The SLF4J detects and uses the concrete logging implementation configured by user. By default, the Logback logging implementation is recommended.

The Logback (or any other logging implementation) must be configured prior to use. Examples of Logback configuration can be found within the JIFH samples. Details about Logback configuration are found here.

Versioning

Semantic Versioning is used for the JIFH. The Handler version includes three components MAJOR.MINOR.PATCH which mean the following:

Advanced Programming

Handler Options

Please see all the available configuration options, their descriptions and default values in the table below.

Option Default Value Description
ConnectivityConfiguration N/A (constructor's argument) Path to the connectivity configuration XML file.
NetworkInterface N/A (constructor's argument) Name of the local network interface on which a multicast group is joined.
LicenseDir N/A (constructor's argument) Path to a directory with license file. The Handler also looks for a license
in the current directory and in the user's home directory.
UdpBufferSize 4194304 Socket buffer size for UDP receiver. If you experience packet losses you may need to increase this value. To test a new value you can use MulticastTest program.
MaxPacketCacheSizeForLiveFeed 300 Max packet cache size for Live feed.
MaxPacketCacheSizeForSnapshotFeed 300 Max packet cache size for Snapshot feed.
StrategyPreference StrategyPreference.NEW Value to be set for the StrategyPreference field for the
Login Request.
TcpSettings Initialized from the
connectivity configuration
Various TCP settings like max number of reconnect attempts and reconnect timeout.
HistoricalReplayEnabled false Enables/disables Historical Replay service to recover lost messages via TCP.
HistoricalReplaySettings See Historical Replay Settings Various Historical Replay settings like response wait time and request rate limit.
LostPacketMaxWaitingTimeInMillis 0 When the Handler detected a packet loss it still can wait for the lost packet(s)
for some time. By default, the Handler doesn't wait for list packets but with
this option this behavior can be changed.
MaxUserCallbackTimeInNanos 10 * 1000000 This option controls max time the Handler spent in user code callback.
If user code exceeds this limit the Handler will add a warning to the log
and call onWarning callback.

Historical Replay Settings

Please see all the available Historical Replay settings, their descriptions and default values in the table below.

Setting Default Value Description
RequestPollingPeriodInMillis 100 Request polling period in milliseconds.
ResponseWaitTimeInMillis 3 * 1000 Response wait time in milliseconds.
MessagesWaitTimeInMillis 60 * 1000 Messages wait time in milliseconds.
PermitsPerSecond 1 The rate of the outgoing Historical Replay requests.
Measured in how many permits become available per second.

Handler State Transition Graph

The following diagram illustrates how the JIFH can change its state.

Handler State Graph

Feed Concept

To receive UDP data from multicast groups the Handler creates entities called Feeds. Each Feed has its own UDP receiver.

UDP receiver is used to receive packets from the socket. Each receiver starts its own thread in which it receives data from the socket and notifies Feed that a new packet is available. When Feed receives such notification it immediately processes the packet and calls callbacks.

If processing is slow, socket buffer may be overflown and this will cause packet loss. To prevent this you need to take a closer look at the time in user callbacks. This is the main source of issues that may cause packet loss. If the user's code in the Handler's callbacks takes too much time you can see the buffer is overflown because new packets come at a higher rate than they processed by the Handler.

If time in a callbacks is more than a configured limit the Handler will call WarningListener.onWarning(WarningEventArgs) with the reason like "Time in user code callback PacketProcessingListener::onPacketReceived() exceeded configured limit (1234 > 1000)". Please use HandlerOptions.setMaxUserCallbackTimeInNanos(long) to adjust the max time for a user callback.

If time in user callbacks is fine, you can also increase socket buffer size using HandlerOptions.setUdpBufferSize(int). This may help if the amount of data sent by ICE is large and with default buffer size you still see packet loss. By default, the socket buffer size is large enough and equal to 4 MiB, but it may be not enough in some cases so you need to keep this Handler's option in mind.

Feed Identification

For every subscription the JIFH starts two feeds - a snapshot and a live. This pair of feeds has a unique integer identifier - feed ID. Some messages (like a Bundle Marker message) can be identified only by feed ID. To get the feed ID, a client should implement the FeedStateChangeListener interface. If the client wants to query if messages are being received by a specific feed ID, it should invoke MessageInfo#getFeedId().

Example

The following example demonstrates how to geed feed ID.
public class MyListener implements BundleMarkerListener {
    private static final Logger LOG = LoggerFactory.getLogger(MyListener.class);

    public void onBundleMarker(BundleMarkerEventArgs args); {
        LOG.debug("feedId(): {}", args.getMessageInfo().getFeedId());
    }
}

Multicast Message Block

Multicast message block concept is introduced by ICE in Multicast ICE iMpact Multicast Feed Message Specification. The Handler organized multicast data processing based on this concept. The data from the header of each message block is available for each message event and represented as an instance of MessageInfo class. This class contains the following properties to get information from the header.

Header Field MessageInfo Getter
Session Number biz.onixs.ice.impact.handler.MessageInfo#getSessionNumber
Sequence Number biz.onixs.ice.impact.handler.MessageInfo#getBlockSequenceNumber
Number of Msgs biz.onixs.ice.impact.handler.MessageInfo#getNumberOfMessagesInBlock
Sent Time biz.onixs.ice.impact.handler.MessageInfo#getSentTime and biz.onixs.ice.impact.handler.MessageInfo#getSentTimeNanos

Message Identification

biz.onixs.ice.impact.handler.MessageInfo is designed to provide access to all the information about incoming message and a feed which received it.

In addition to the above information from multicast message block header this class provides access to the following:

Field Description
Feed ID Identifier of the feed which received this message
Session Number This number is assigned by ICE and indicates which session is active
Sequence Number All the multicast messages blocks have this number to make it possible to process them in correct sequence
Number of Messages In Block Indicates how many messages are in the multicast message block
Sent Time ICE sets this timestamp as number of milliseconds or nanoseconds (depends on feed)
Receive Time Time when the packet was received by Handler from UDP, in nanoseconds
Multicast Message Type The type of the message received

Log Replay

Log replay feature provides the ability to save time and money when to pay for connection to the Production Environment and this takes a lot of money. Instead of this the Handler can record all events occurring on the Exchange and in the future be able to play them repeatedly. All you need to do is to save log files.
Data Sources for Log Replay

The Handler can replay log data from the following sources:

Log Replay From Log File

To replay data from the Handler's log file you need to add a path to this file to the list of log files to replay. You can do this using biz.onixs.ice.impact.handler.LogReplayOptions.addLog method.

You alson need to make sure the Handler will be able to parse TCP and UDP data in this file. By default, the Handler is configured to read data for replay using regular expressions which match corresponding lines in the format produced by C++ version of the Handler.

Here are the example log line with TCP data:

20170921-10:34:58.535 [Handler] TCP message body received (QgK...AQA=).

and UDP:

20170921-10:37:40.684  [Feed '233.156.208.229:20229'] Received Kv8AABSWAAAAAAFepAPSBg==

Corresponding regular expression for this format are the following:

Data Regex to match data
TCP
([0-9-.:]+).*\[(.*)\] TCP.*received ([^\(]*)\((.*)\).*
UDP ([0-9-.:]+) \[(.*)\] Received (.*)\..*

Both of these regular expressions need to capture the following:

To adjust the Handler for your log file format please use the following methods:

Data How to set new regex?
TCP
biz.onixs.ice.impact.handler.LogReplayOptions.setTcpDataPattern(String)
UDP
biz.onixs.ice.impact.handler.LogReplayOptions.setUdpDataPattern(String)

These methods need to be used only if you have a special format which is not compatible with the current regular expressions.

Replay Multiple Log Files

The Handler can generate more than one log file. This depends on the Handler's settings but if you want to record the whole trading day and then replay this data you will need to deal with multiple log files.

In order to replay the data from the multiple log files you need to add all the log files using HandlerOptions.addLog(String) method in the order they have been created. You should keep this order as there is no logic to sort the log records and the Handler will just read all the data sequentially.

NOTE: Log replay for multiple sessions is not supported. If you started and stopped the Handler several times for a single log file the log replay can't be used as it will normally replay the first session and then failed.

Connectivity Configuration Structure

All JIFH options are exposed and edited within the biz.onixs.ice.impact.handler.HandlerOptions class and this contains a path to the connectivity configuration file. This file contains definitions of multicast groups and the network addresses of corresponding servers with which the JIFH has to connect so as to receive market data. There are three major logical groupings of parameters which combine to make the configuration: the TCP connection information, Multicast groups and Market types.

TCP Connection Information

The TCP connection information section defines the attributes of the remote system to which a server connects to request primary information such as product definitions for selected markets. This section also defines security information such as username and password which are mandatory for the JIFH instance.

Typical TCP connection information section looks as follows:

   <server name="ICE"/>
     <ip>63.247.113.163</ip>
     <port>443</port>
     <userName>Value from ICE Support</userName>
     <password>Value from ICE Support</password>
     N
     N
     <strategyPreference>New</strategyPreference>
     <localNetworkInterface></localNetworkInterface>
     <sslEnabled>Y</sslEnabled>
   </server>

The values of IP address and port attributes define the connection to the remote system.

The userName and password are the logon-related attributes.

To get Strip Info messages you need to explicitly set getStripInfoMessages to Y.

To get Strip Info messages for strategies you need to explicitly set getStripInfoForStrategies to Y.

SSL connection enabled by default but if for any reason you need to switch back to plain TCP connection just use sslEnabled to N.

How To Specify Username And Password Using API?

If you don't want to store username and password in the connectivity configuration file, please use the Handler's API. For example:
    // Create the Handler settings and specify config file.
    String connectivityConfiguration = settings.getString("ConnectivityConfiguration");
    String networkInterface = settings.getString("NetworkInterface");
    String licenseDir = settings.getString("LicenseDir");

    HandlerOptions handlerOptions = new HandlerOptions(connectivityConfiguration, networkInterface, licenseDir);

    // When the Handler is created, `TcpSettings` object is created as well
    // from the data in the connectivity configuration file.
    // You can keep username and password empty in the config file.
    Handler handler = new Handler(handlerOptions);

    // Now set the username and password.
    // All other settings will be the same as specified in the config file.
    handler.setTcpServerCredentials("username", "password");

New Market Types

From time to time ICE publishes information about new market types. To get the latest version of connectivity configuration files please use this link.

If there is no required market type in the connectivity configuration files, there are following options available:

  1. Contact OnixS Support and ask to add a new market type.
  2. Create a ticket in OnixS Jira and describe which market type is required.
  3. Add the new market type on your own.

To add a new market type manually please do the following:

  1. Download the latest version of the "Supported Market Types on ICE API".
  2. Find a row with the required market type.
  3. Find a name of a multicast group(s) in the "iMpact Pricefeed - Multicast Grp(s)" column. Usually the first group is for Futures and the second is for Options.
  4. Check if the multicast group is available in a connectivity configuration xml file. The name of the group can be found in the "name" attribute of the "connectivityConfiguration/multicast/group" xml node.
  5. If the multicast group does not exists, please add the new "connectivityConfiguration/multicast/group" xml node with the corresponding name and fill it with IP addresses and ports from the "ICE Multicast Connectivity Guide" (for Production) and from the "ICE iMpact Multicast Feed Technical Specification" (for AP1 and PF1).
  6. If the multicast group exists, add the "connectivityConfiguration/allMarketTypes/marketType" xml node.
  7. The market type code from first column "ID" should be specified in the "code" attribute.
  8. The multicast group for Futures should be specified in the "multicastGroup" attribute.
  9. The multicast group for Options should be specified in the "optionsMulticastGroup" optional attribute.
  10. The name of the new market type from the "Market Type Name" column should be specified as an inner text of the "connectivityConfiguration/allMarketTypes/marketType" xml node.

Order Book

Switch Off Order Book Processing

Order book processing is disabled when OrderBookListener is not registered via biz.onixs.ice.impact.handler.Handler#registerOrderBookListener. Otherwise it is enabled.

Incremental Updates Processing

The JIFH provides the ability to receive and process incremental updates to order books.

To process incremental updates to a Full Order Depth (FOD) book, a client should implement an interface of FullOrderDepthBookChangeListener and register a listener using Handler#registerFullOrderDepthBookChangeListener.

To process incremental updates to a Price Level (PL) Book, a client should implement an interface of PriceLevelBookChangeListener and register a listener using Handler#registerPriceLevelBookChangeListener.

The table below shows the BookChangeType enum values and corresponding ICE iMpact messages for FOD with their short description.

BookChangeType Full Order Depth message Description
UNKNOWN n\a Default value
SNAPSHOT Market Snapshot Order Message This message is for orders in snapshot only. It is different to order message for incremental updates.
ADD Add/Modify Order Message Both add and modify order notifications use one message format. A client should add the order to book if it is not already there. Otherwise, just overwrite the existing order.
CHANGE Add/Modify Order Message Both add and modify order notifications use one message format. A client should add the order to book if it is not already there. Otherwise, just overwrite the existing order.
REMOVE Delete Order Message Upon receipt of this message, a client should remove the order from it local book. Under certain scenarios, the message could be sent from the backend with an OrderID that does not exist on the client's book, in which case the client can just ignore it.

The table below shows the BookChangeType enum values ​​and corresponding ICE iMpact messages for PL with their short description.

BookChangeType Price Level message Description
UNKNOWN n\a Default value
SNAPSHOT Market Snapshot Price Level Message This message is for price level in snapshot only. For a given market, these messages follow directly after Market Snapshot Message.
ADD Add Price Level Message Upon receipt of this message, a client should add/insert a price level into the requisite position in the order book for the market specified. Existing price levels move down the stack if they were previously at or worse than the new entry. When the total number of levels with an order book exceeds what is supported (e.g. Top 5), the client should remove the bottom level. The exchange doesn't send out Delete Price Level message in this scenario.
CHANGE Change Price Level Message Upon receipt of this message, a client should update the price level at the specified position in its book for the given market.
REMOVE Delete Price Level Message Upon receipt of this message, a client should remove the price level in the order book for the market specified. All the levels that were worse that the level removed climb up the stack.

Implied Prices

The Handler supports both implied and non-implied feeds. For more details about implied prices please see ICE Futures Implied Prices.

Subscribing To Multicast Groups

Product Identification

ICE provides many market types available for subscription. The full list is available in the Supported Market Types on ICE API document. Please use a value in the first column, ID, as a value for the first constructor's argument of MarketSubscription.

When you don't know which market type ID should be used you can check this on All Futures, Options, OTC Products & Physicals site. There are many products available so you can review and select what you need. After this you can click Product Codes to get information about the mapping and find the market type name. With this information you can easily determine which market type ID should be used using Market Type Name column in the Supported Market Types on ICE API document.

Creating Subscription

The ICE iMpact multicast groups are currently defined based on a set of products (such as Europe Futures Oil) and depth of book (Full Order Depth, Top 5 Price Level). The Handler exposes the flexibility of subscribing to the multicast groups that are best suited to customers individual needs.

Subscribing is a way to start receiving Multicast Price Feed market data. To subscribe to certain multicast groups as well as to select which type of books must be maintained by the Handler, an instance of a list of MarketSubscription objects must be created and filled with items.

Once the instance is created, subscriptions for a particular market type can be added. This can be achieved by pushing items of type MarketSubscription into the collection. Each added item identifies the type of market to which subscription will be performed and kinds of books which the Handler is supposed to build and update while maintaining a subscription.

Depending on security type the following order book depths are available:

Security Type Order Book Depth
Futures TOP5PL or FOD
UdsFuturesMarkets TOP5PL or FOD
Options TOB or TOP10PL
UdsOptionsMarkets TOB or TOP10PL

Filtering

It is possible to specify one or more market ID for each market subscription using biz.onixs.ice.impact.handler.MarketSubscription.setMarketIds method. This ID will be added to a set which is used as a first-level filter and all product definitions which do not match this set will be ignored.

The second-level filter is a special boolean parameter isInterested which is available in the following events:

This parameter can be used to determine if a subscription for a given product definition should be maintained or not. By default, this value is set to true. If the given product definition is not interested you just need to set it to false and it will be removed from market subscription and the Handler won't process any messaged with this market ID.

The Handler can maintain as much first- and second-level filters as needed. There are no limitations to this kind of settings in the Handler implementation.

Cross Filtering

If you need to filter one set of product definitions depending on information from another set of product definitions like you want to maintain only those Futures product definitions which related to UdsFuturesMarkets you are interested in you can use the following approach:

  1. Make two subscriptions - for UdsFuturesMarkets and for Futures.
  2. The UdsFuturesMarkets subscription should be first in the list.
  3. In your code allocate some array to keep market IDs of the legs.
  4. When you receive the UdsFuturesMarkets with legs you want to subscribe you need to add its IDs to your array.
  5. When you receive the Futures you need to check if a market ID is in your array and set IsInterested to true.

Starting Subscription

Afterward, the constructed collection must be passed to biz.onixs.ice.impact.handler.Handler.start method which causes the Handler to receive and process data for the markets specified in the subscription. Since that moment, the Handler will notify about all the events through appropriate listeners. In particular, it will notify the subscribers about the reception of the product definitions. Later, about changes in states of markets, new orders added or removed to or from market books, and, surely, about errors if any occurred during processing data from Multicast Price Feed channels.

Product Definitions Recovery

After biz.onixs.ice.impact.handler.Handler.start method is called the Handler establishes an SSL connection to the ICE server and sends Login Request. If login is successful and Login Response does not indicate any error the Handler starts security definition recovery.

To indicate this the Handler has two states:

  1. biz.onixs.ice.impact.handler.HandlerState.SECURITY_DEFINITIONS_RECOVERY_STARTED
  2. biz.onixs.ice.impact.handler.HandlerState.SECURITY_DEFINITIONS_RECOVERY_FINISHED

The first state is indicating that the Handler just started security definition recovery and only going to send a product definition request. The second state is indicating that all the product definitions downloaded successfully and the Handler is going to start book resynchronization.

To download all the required product definitions the Handler uses a set of market subscriptions which are passed to biz.onixs.ice.impact.handler.Handler.start method. Each product definition request requires market type and security type so this information is extracted from subscriptions. For example, if a user wants to download product definitions for the following market subscriptions:

MarketSubscription(5, SecurityType.FUTURES, OrderBookType.FULL_ORDER_DEPTH);
MarketSubscription(5, SecurityType.UDS_FUTURES_MARKETS, OrderBookType.FULL_ORDER_DEPTH);

The handler will send two product definition requests. For each of these requests, the Handler should receive all the available product definitions or Error Response if there are no product definitions for the requested parameters. The Handler automatically handles such Error Responses and if an error is not critical it continues working. In case the error is critical and indicate something else and not the absence of requested product definitions the Handler will notify user code and stop.

Example

Below is the example of creating subscription for IPE Brent Futures market of ICE Futures Brent multicast group:

List subscriptions = new ArrayList<>();
MarketSubscription marketSubscription = new MarketSubscription(
    5                       // Market type id for IPE Brent Futures.
  , SecurityType.FUTURES    // Defines type of securities (Futures/OTC, Options or UDS Markets)
  , OrderBookType.TOP5PL    // Build and maintain Top5PL book.
  );
subscriptions.add(marketSubscription);
handler.start(subscriptions);

Product Definitions

Types of Product Definitions

The ICE Exchange provides following types of product definitions:

The product definitions could be received in two ways:

The table below describes how the product definitions represented in the OnixS ICE iMpact Multicast Price Feed Handler API:

Product Definition Security Type Callback (TCP) Callback (UDP)
Futures/OTC biz.onixs.ice.impact.handler.SecurityType.FUTURES biz.onixs.ice.impact.handler.event.FuturesProductDefinitionListener.onFuturesProductDefinition biz.onixs.ice.impact.handler.event.NewExpiryListener.onNewExpiry
Options biz.onixs.ice.impact.handler.SecurityType.OPTIONS biz.onixs.ice.impact.handler.event.OptionsProductDefinitionListener.onOptionsProductDefinition biz.onixs.ice.impact.handler.event.NewOptionsMarketDefinitionListener.onNewOptionsMarketDefinition
Options Strategy biz.onixs.ice.impact.handler.SecurityType.UDS_OPTIONS_MARKETS biz.onixs.ice.impact.handler.event.OptionsStrategyDefinitionListener.onOptionsStrategyDefinition biz.onixs.ice.impact.handler.event.NewOptionsStrategyDefinitionListener.onNewOptionsStrategyDefinition
Futures Strategy biz.onixs.ice.impact.handler.SecurityType.UDS_FUTURES_MARKETS biz.onixs.ice.impact.handler.event.FuturesStrategyDefinitionListener.onFuturesStrategyDefinition biz.onixs.ice.impact.handler.event.NewFuturesStrategyDefinitionListener.onNewFuturesStrategyDefinition

Receive Product Definitions Only

The Handler provides a special mode when it only receives product definitions and then stopped. To activate this mode you need to use biz.onixs.ice.impact.handler.HandlerOptions.setReceiveProductDefinitionsOnly and set this option to true. After this, you can create and start the Handler in the usual way, but the behavior will be different. The Handler establishes a TCP connection to the ICE server, sends a Login request, and according to market subscriptions, sends Product Definition requests. When all the requested product definitions are received, the Handler stops. The Handler's state changes in the following sequence:

  1. biz.onixs.ice.impact.handler.HandlerState.STOPPED
  2. biz.onixs.ice.impact.handler.HandlerState.LOGIN_IN_PROGRESS
  3. biz.onixs.ice.impact.handler.HandlerState.SECURITY_DEFINITIONS_RECOVERY_STARTED
  4. biz.onixs.ice.impact.handler.HandlerState.SECURITY_DEFINITIONS_RECOVERY_FINISHED
  5. biz.onixs.ice.impact.handler.HandlerState.STOPPED

This mode is using, if you want to periodically update information about product definitions in your local store and have a simple implementation without tracking the Handler state and calling the biz.onixs.ice.impact.handler.Handler.stop method to stop the Handler.

Listening to events of the ICE iMpact Handler

Events in the JIFH

There are five major events exposed by the JIFH:

Once the JIFH is started, it listens to market data from the network, processes it (decodes messages, validates message order, updates order books) and invokes the client code for further processing.

The JIFH processes market data asynchronously and uses a concept of events and event listeners to notify the client code about particular activity such as receipt of security definitions or book updates.

Listening For Specific Events

For every event type such as Error Occurred the JIFH exposes a corresponding interface such as biz.onixs.ice.impact.handler.event.ErrorListener. The client code must implement this interface to be able to receive events of each type. The JIFH also exposes a member such as biz.onixs.ice.impact.handler.Handler#registerErrorListener. Thus an instance of the event handler may be associated with an appropriate inbound event of a particular instance of the biz.onixs.ice.impact.handler.Handler class.

Note
Associating a listener for a particular event with an instance of the biz.onixs.ice.impact.handler.Handler class must be performed while the Handler is in stopped stated. Once the JIFH has started then modifying the listener-event associations is not permitted, it may lead to unpredictable behaviour and cause unexpected errors..

Associating an event listener with an instance of the biz.onixs.ice.impact.handler.Handler class is also called subscribing to an event.

All listener interfaces are in the biz.onixs.ice.impact.handler.event namespace.

Event Listener interface to be implemented JIFH member to register listener Description
Futures/OTC Product Definition Received FuturesProductDefinitionListener registerFuturesProductDefinitionListener Fired by the JIFH when subscription is started. The JIFH calls an associated listener (an event handler) for each product definition it receives. Invocation of the event handler is performed in the same thread in which the Handler#start member was called. Once the subscription has successfully started events of this type will not be fired for subscribed markets again (until the next restart).
Strip Info Received StripInfoListener registerStripInfoListener Fired by the JIFH when subscription is started. The JIFH calls an associated listener (an event Handler) for each strip info messages it receives. Invocation of the event handler is performed in different threads.
Options Product Definition Received OptionsProductDefinitionListener registerOptionsProductDefinitionListener Fired by the JIFH when subscription is started. The JIFH calls an associated listener (an event handler) for each product definition it receives. Invocation of the event handler is performed in the same thread in which Handler#start member was called. Once the subscription has successfully started events of this type will not be fired for subscribed markets again (until the next restart).
Options Strategy Definition Received OptionsStrategyDefinitionListener registerOptionsStrategyDefinitionListener Fired by the JIFH when subscription is started. The JIFH calls an associated listener (an event handler) for each product definition it receives. Invocation of the event handler is performed in the same thread in which Handler#start member was called. Once the subscription has successfully started events of this type will not be fired for subscribed markets again (until the next restart).
Order Book Changed OrderBookListener registerOrderBookListener Fired by the JIFH when order book is changed. Invocation of the event handler is performed in different threads.
Price Level Book Change Received PriceLevelBookChangeListener registerPriceLevelBookChangeListener Fired by the JIFH when PL order book change is received. Invocation of the event handler is performed in different threads.
Full Order Depth Book Change Received FullOrderDepthBookChangeListener registerFullOrderDepthBookChangeListener Fired by the JIFH when FOD order book change is received. Invocation of the event handler is performed in different threads.
Market State Changed MarketStateListener registerMarketStateListener Fired by the JIFH when market state is changed. Invocation of the event handler is performed in different threads.
Trade Occurred TradeListener registerTradeListener Fired by the JIFH when trade occurred. Invocation of the event handler is performed in different threads.
End of Day Market Summary Message Received EndOfDayMarketSummaryListener registerEndOfDayMarketSummaryListener Fired by the JIFH when End of Day Market Summary message is received. Invocation of the event handler is performed in different threads.
RFQ Message Received RfqListener registerRfqListener Fired by the JIFH when RFQ message is received. Invocation of the event handler is performed in different threads.
Interval Price Limit Notification Message Received IntervalPriceLimitNotificationListener registerIntervalPriceLimitNotificationListener Fired by the JIFH when IPL Notification message is received. Invocation of the event handler is performed in different threads.
System Text Message Received SystemTextListener registerSystemTextListener Fired by the JIFH when System Text message is received. Invocation of the event handler is performed in different threads.
Handler State Changed HandlerStateListener registerHandlerStateListener Fired by the JIFH when it's state is changed. Invocation of the event handler is performed in different threads.
Error Occurred ErrorListener registerErrorListener Fired by the JIFH when error occurred. Invocation of the event handler is performed in different threads.
Warning Occurred WarningListener registerWarningListener Fired by the JIFH when warning occurred. Invocation of the event handler is performed in different threads.
Log-replay Error Occurred LogReplayListener registerLogReplayListener Fired by the JIFH when log-replay error occurred. Invocation of the event handler is performed in different threads.
Log-replay Finished LogReplayListener registerLogReplayListener Fired by the JIFH when replay log is finished. Invocation of the event handler is performed in different threads.

Example

The following sample demonstrates how to listen to notifications for the receipt of security definitions.
public class MyListener implements FuturesProductDefinitionListener {
    private static final Logger LOG = LoggerFactory.getLogger(MyListener.class);

    public void onFuturesProductDefinition(FuturesProductDefinitionEventArgs args) {
        LOG.debug("onFuturesProductDefinition(): {}", args);
    }
}

public class Sample {
    private void run() throws Exception {
      final HandlerOptions handlerOptions = new HandlerOptions();
        final Handler handler = new Handler(handlerOptions);
        // ...
        final MyListener listener = new MyListener();
        handler.registerFuturesProductDefinitionListener(listener);
    }
}

Packet Processing Listener

Packet Processing Started Event

Each time the Handler receives a new multicast message block with at least one messages inside it this event will be triggered. Multicast message blocks without messages (i.e. heartbeats) do not trigger this event.

Packet Processing Finished Event

When all the messages in the current multicast message block have been processed the Handler triggers this event. This is a pair for onPacketProcessingStarted and this event will always follow it.

Packet Received Event

This event will be triggered for each TCP data block and each UDP datagram. Please pay attention that UDP packets can be out of order.

Health Check

Health Check Metrics

The main metric currently exposed by the Handler is Handler's state. It is accessible through biz.onixs.ice.impact.handler.Handler.getState() method. After the initial recovery, the Handler normally operates in the BOOKS_RESYNCHRONIZATION_FINISHED state. If the state is STOPPED it means that the Handler either stopped or faced with unrecoverable error and this can be treated as a failed health check.

The typical way how one can implement health checking for the Handler is by subscription to the following events:

Information about warnings and errors can help with diagnostics. States can be useful to track the current activity of the Handler and its feeds.

Error Handling

Being a Java library, the JIFH uses exceptions to report any errors arising. For example, the JIFH will raise a regular exception to report the inability to find a current license for the product. However, the JIFH processes market data asynchronously therefore is not able to report any further errors after market data processing is started. For this reason, the JIFH has to expose the biz.onixs.ice.impact.handler.event.ErrorListener interface and the biz.onixs.ice.impact.handler.Handler#registerErrorListener member to be able to subscribe to and handle errors.

Once an instance of the biz.onixs.ice.impact.handler.event.ErrorListener is assigned to the JIFH, it will invoke the biz.onixs.ice.impact.handler.event.ErrorListener#onError member every time an error occurs. The biz.onixs.ice.impact.handler.event.ErrorListener#onError member has several configurable parameters one of which defines a human-readable explanation (description) of the error.

An important aspect of the JIFH behaviour is that in normal use there is nothing special required to handle errors. In particular, once the subscription to market data has started successfully then the JIFH will process incoming market data and handle all recovery failures without any additional user action being required. There is no need to restart a subscription for market data manually as the JIFH recovery logic is designed for optimal recovery and will address non-fatal errors. Also, the JIFH recovers from detected errors in the optimal way. For example, in the event of a network-related issue the JIFH will rebuild only those books and market states which are based on market data from the problematic multicast feed channel. It will not invalidate and rebuild entire subscription for non-impacted channels.

Example

The following sample demonstrates how to receive error notifications.

public class MyListener implements ErrorListener {
    private static final Logger LOG = LoggerFactory.getLogger(MyListener.class);

    public void onError(ErrorEventArgs args) {
        LOG.debug("onError(): {}", args);
    }
}

public class Sample {
    private void run() throws Exception {
    final HandlerOptions handlerOptions = new HandlerOptions();
        final Handler handler = new Handler(handlerOptions);
        // ...
        final MyListener listener = new MyListener();
        handler.registerErrorListener(listener);
    }
}

Supported ICE iMpact Multicast Feed Message Specification

ICE iMpact Multicast Price Feed Handler supports ICE iMpact Multicast Feed Message Specification version 1.1.49 (10 May 2024).

Samples

PCAP Replay Sample

To demonstrate how to feed the Handler with TCP and UDP data from PCAP we have added pcap-replay sample to the distribution package. This sample is distributed without any .pcap file but it can be provided by request.

pcap-replay sample is implemented on top of the Handler's feature to read log data from a custom source. In this implementation, we just read PCAP data and convert it to the format compatible to the Handler's expectations.

Conformance Testing

This section provides information about the status of conformance testing and uncovers some questions about the process.

API Certification Results

Onix Solutions has PASSED iMpact Multicast Conformance as a Independent Software Vendor using "OnixS ICE iMpact Multicast Price Feed Handler".

SCRIPT: iMpact Multicast Feed API Conformance, Version 17.1, January 15, 2020

DATE: 16 January 2020

Conformance Script Questions

Question Answer
Have you coded to the ICE Multicast Feed Message Spec (Section 2.2)? Yes
Can you handle dynamic LegBodyLength? Yes
Can you handle NumberOfExtraLegDefinitions? Yes
Do you support Market Identifier Codes (MIC)? Yes
If yes, do you get it from the Contract Symbol of the product definition response message (message type=B)? Yes
Do you process message bundle markers (message type=T)? The Handler only parses these messages and notifies the user code. No other processing is implemented on the Handler side. So, if you have no logic related to Bundle Marker the answer for this question is "No".

Multicast Tunnel Proxy

What is it?

For the test environment, the multicast tunnel proxy can be used to receive multicast messages through a TCP tunnel.

How to install?

Multicast tunnel proxy utility is available as part of ICE iMpact Multicast Price Feed Getting Started package which can be obtained from by contacting ICE Support.

How does it work?

The tunnel proxy establishes a socket connection to the feed server, receives the messages and multicasts them on the local network based on the multicast group mapping rules from TunnelProxy.properties file.

Once the tunnel proxy is launched, the multicast client can join the local multicast channels that the tunnel is currently multicasting. This provides a seamless operation from the clients' perspective. The diagram below illustrates the connectivity:

Multicast Tunnel Proxy

The tunnel TCP server address is 63.247.113.163. But the tunnel port could be different depending on the multicast groups. You can find the port numbers under connection info for API Test env in ICE iMpact Multicast Feed Technical Specification.

How to specify a network interface?

Configuration parameter tunnel.multicast.interface in the TunnelProxy.properties file could be used.
#
# In case you want to multicast on a specific interface, or if your local
# network doesn't support # multicast, you can uncomment the following property.
# This property sets the multicast interface to 127.0.0.1
#
tunnel.multicast.interface=127.0.0.1
Note
The value 127.0.0.1 works perfectly in most cases.

Connectivity Troubleshooting

Issues related to receiving multicast data

In most cases, absence of multicast data is caused by network-related configuration issues described below.

Firewall blocks program and GettingStarted sample

Updating firewall rules or simply turning it off usually solves the issue.

NOTE: Disabling firewall explicitly may be dangerous. Consult your network and system administrator before turning firewall off.

Explicit network interface should be specified

GettingStarted sample program configures the Handler to listen to market data on the loopback network interface on Windows and Linux.

If network configuration supposes specifying exact network interface (like 'eth0' on Linux) for market data listening, then biz.onixs.ice.impact.handler.HandlerOptions.setNetworkInterface() method should be used to update the value accordingly.

More Information

More information can be found in our Lost multicast packets troubleshooting guide.

Multicast Test

Multicast Test is a simple program written in C++ that may be used to test multicast feed connections and to troubleshoot multicast issues.

This utility can be downloaded using this link (login and password available by request).

How Multicast Test works?

For example, the following command checks the availability of ICE Futures Brent, Price Level, Live Feed:

> MulticastTest --verbose --ip 233.156.208.228 --port 20228 --interface 127.0.0.1 --maxPackets 30
ip: 233.156.208.228
port: 20228
interface: 127.0.0.1
timeout: 30
maxPackets: 30
Creating socket
Setting SO_REUSEADDR
Setting SO_RCVTIMEO
Initializing socket address
Binding
Initializing mcast request
Initializing interface address
Joining mcast group
Date: 07/15/2013
    Time         Bytes        Packets
Entering test loop
11:45:21           572              4
11:45:22          1573             11
11:45:23          2574             18
11:45:24          3432             24
11:45:25          4433             31

FAQ

What is the difference between "Book Changed" and "Book Change Received" events?

If you subscribe to Order Book Changed, you will always have a consistent book. Price Level Book Change Received and Full Order Depth Book Change Received callbacks are designed for those who want to build and maintain books by themselves. Order Book Changed is an elementary action over the order book. As a rule there are multiple changes inside single snapshot and/or incremental refresh. For this reason, a book may not be valid between two changes. Only when all the changes are processed from the single network data (message like a snapshot and incremental refresh), the book is considered as valid. Book Change Received callbacks are called precisely at the time when all changes have been processed and a book appears to be valid and up-to-date.

How to work around "Login request rejected because last attempt was fewer than 15 seconds ago"?

This is an exchange's limitation and to work around this issue you need to implement throttling mechanism in your application. This issue may happen when biz.onixs.ice.impact.handler.Handler.start() is called without timeout between attempts.


© Onix Solutions