Version 1.60.0
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):
Supported Java version is 1.8.*.
The list of compatible JDKs:
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.
For those who are unfamiliar with the JIFH we recommend that you take the following actions in priority sequence:
biz.onixs.ice.impact.handler.Handler
class.biz.onixs.ice.impact.handler.Handler#start
member.biz.onixs.ice.impact.handler.Handler#stop
member.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);
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.
Semantic Versioning is used for the JIFH.
The Handler version includes three components MAJOR.MINOR.PATCH
which mean the following:
MAJOR
version for incompatible API and behavior changes;MINOR
version for new functionality in a backward-compatible manner;PATCH
version for backward-compatible bug fixes.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 theLogin 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.
|
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. |
The following diagram illustrates how the JIFH can change its state.
To receive UDP data from multicast groups the Handler
creates entities called Feed
s.
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.
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()
.
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 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
|
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 |
The Handler can replay log data from the following sources:
java.io.InputStream
object with access to data for log replay.biz.onixs.ice.impact.handler.LogReader
interface.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-.:]+) |
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.
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.
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.
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
.
// 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");
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:
To add a new market type manually please do the following:
Order book processing is disabled when OrderBookListener
is not registered via
biz.onixs.ice.impact.handler.Handler#registerOrderBookListener
. Otherwise it is enabled.
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. |
The Handler supports both implied and non-implied feeds. For more details about implied prices please see ICE Futures Implied Prices.
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.
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 |
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:
biz.onixs.ice.impact.handler.event.FuturesProductDefinitionEventArgs
biz.onixs.ice.impact.handler.event.FuturesStrategyDefinitionEventArgs
biz.onixs.ice.impact.handler.event.OptionsProductDefinitionEventArgs
biz.onixs.ice.impact.handler.event.OptionsStrategyDefinitionEventArgs
biz.onixs.ice.impact.handler.event.NewExpiryEventArgs
biz.onixs.ice.impact.handler.event.NewFuturesStrategyDefinitionEventArgs
biz.onixs.ice.impact.handler.event.NewOptionsMarketDefinitionEventArgs
biz.onixs.ice.impact.handler.event.NewOptionsStrategyDefinitionEventArgs
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.
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:
UdsFuturesMarkets
and for Futures
.UdsFuturesMarkets
subscription should be first in the list.UdsFuturesMarkets
with legs you want to subscribe you need to add its IDs to your array.Futures
you need to check if a market ID is in your array and set IsInterested to true.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.
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:
biz.onixs.ice.impact.handler.HandlerState.SECURITY_DEFINITIONS_RECOVERY_STARTED
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.
Below is the example of creating subscription for IPE Brent Futures market of ICE Futures Brent multicast group:
Listsubscriptions = 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);
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 |
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:
biz.onixs.ice.impact.handler.HandlerState.STOPPED
biz.onixs.ice.impact.handler.HandlerState.LOGIN_IN_PROGRESS
biz.onixs.ice.impact.handler.HandlerState.SECURITY_DEFINITIONS_RECOVERY_STARTED
biz.onixs.ice.impact.handler.HandlerState.SECURITY_DEFINITIONS_RECOVERY_FINISHED
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.
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.
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.
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. |
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); } }
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.
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.
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.
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:
biz.onixs.ice.impact.handler.listener.ErrorListener
biz.onixs.ice.impact.handler.listener.WarningListener
biz.onixs.ice.impact.handler.listener.HandlerStateListener
biz.onixs.ice.impact.handler.listener.FeedStateListener
Information about warnings and errors can help with diagnostics. States can be useful to track the current activity of the Handler and its feeds.
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.
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); } }
ICE iMpact Multicast Price Feed Handler supports ICE iMpact Multicast Feed Message Specification version 1.1.49 (10 May 2024).
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.
This section provides information about the status of conformance testing and uncovers some questions about the process.
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
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". |
For the test environment, the multicast tunnel proxy can be used to receive multicast messages through a TCP tunnel.
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.
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:
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.
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
In most cases, absence of multicast data is caused by network-related configuration issues described below.
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.
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 can be found in our Lost multicast packets troubleshooting guide.
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).
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
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.
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.