Introduction
The EU’s Markets in Financial Instruments MIFID II Directive, will introduce significant changes for investment firms and other financial markets participants when the EU member states implemented them in January 2018. This article discusses the capability for existing TREP clients to transmit pre-trade FIX messages to registered Approved Publication Arrangements (APA) to satisfy MIFID II regulatory requirements.
In many cases, data subject to pre-trade reporting obligations is already available via TREP in the form of MarketPrice updates which are shared via OMM posts. The OMM to FIX Gateway will act as an additional endpoint for OMM post messages, and convert them to FIX format using a simple transformation directive and forward them to the configured APA for processing.
The OMM to FIX Gateway connects to APAs via the FIX protocol using the QuickFIX/J engine, logs all FIX traffic, and support a simple management interface.
Due to limitations of the TREP Post mechanism, the gateway ACKs or NACKs the receipt of messages after they are successfully converted, but before they are routed over FIX to the APA.
TREP Requirements
The OMM to FIX gateway is compatible with TREP versions 2 and 3. Messages are delivered to it with on-stream or off-stream OMM Post messages.
OMM to FIX Gateway Requirements
The OMM to FIX gateway requires any machine running Java, with a minimum of 2GB of memory. Gradle is also required to build the OMM to FIX gateway and pull down dependencies. Docker is required to run the Docker image if you chose that option.
Downloading and building
The zip file containing the OMM to FIX gateway Java source, build scripts and Refinitiv libraries can be downloaded and unzipped on any machine running Java and Gradle.
In the directory containing the file build.gradle, run the command “gradle makeDist“. This will create a file named apagateway_dist.tar.gz. This file can then be moved to the location from where the OMM to FIX gateway will be run.
Building a Docker image
Included in the downloaded zip file is a Dockerfile that can be used to create a Docker image. Run “docker build -t e3pa-gateway:latest" from the directory with the Dockerfile.
Directory Structure
package/ -- root directory
app/ -- all software for the gateway
client/omm/ -- FIX and UPA dictionaries
rules/ -- rules.json file location
gateway.sh -- script to start E3PA
utils.sh -- script used by gateway.sh
Running the OMM to FIX gateway server
The OMM to FIX gateway can be run from a shell script or can be run from a Docker image. Both methods are described below.
To start the OMM to FIX server extract the apagateway_dist.tar.gz file created after you ran the gradle build and go to the package directory. Run the gateway.sh with the --server option to start the server. There are many command line options available:
gateway.sh --server <command-line options>
TREP options
-a --adhuser ADH user id
-i --serviceid TREP service id to advertise
-y --service TREP service name to advertise
-f --fixdictionary FIX dictionary file
-x --fixenums FIX enums
-q --postdictionary OMM Post dictionary
-w --postenums OMM Post enums
FIX options
-s --sender FIX sender comp ID
-t --target FIX target comp ID
-e --fixaddress Remote APA FIX host/ip
-g --fixport Remote APA FIX port
-k --version FIX version (typically FIXT.1.1 for APA)
-st --starttime FIX connection start time (hh:mm:ss)
-et --endtime FIX connection end time (hh:mm:ss)
-j --heartbeat FIX heartbeat interval, default: 30 seconds
Logging/Config options
-R --rulesfile path to transformation rules file
-fl --filelog FIX file log path
-z --json JSON log path
A sample start command might look like:
./gateway.sh --server -a rmds -i 256 --service AUTEX_APA -s AUTEX -t APA_DEST -e 198.100.10.92 -g 7000 -k FIXT.1.1 --fixdictionary ./client/omm/FDMFixFieldDictionary --fixenums ./client/omm/FDMenumtypes.def --postdictionary ./client/omm//RDMFieldDictionary --postenums ./client/omm/enumtype.def --rulesfile ./rules/rules.json --filelog ./logs --json ./logs
Defining JSON Transformation Rules
In order to convert OMM Post messages to FIX, you must specify mapping logic in a JSON file. The rules will be applied to each incoming post message and applied to convert it to FIX to be sent to the APA destination.
We have included sample rules files that follow a few APA pre-trade FIX specs, but since the OMM Post dictionaries are highly customized by clients, each user will need to tweak the JSON transformation rules to capture the OMM Post fields.
Let’s say we wish to define a JSON file to map OMM Post messages to the TRADEcho pre-trade quote offer FIX message. We will make the following assumptions as to the FID tags and values in the post message:
OMM Header key ITEMNAME = security id
8633 = quote id
16 = trade date
18 = trade time
25 = offer px
31 = offer size
The FIX spec for TRADEcho requires the following tags in the body:
35 = i (quote)
117 = QuoteId
60 = Timestamp for the quote (TransactTime)
296 = NoQuoteSets
295 = NoQuoteEntries
48 = Security ID
22 = Security ID Source (4 = ISIN, etc.)
133 = OfferPx
135 = OfferSize
So we need to construct a JSON transformation rule that tells the OMM to FIX gatweay to do the following:
1. Make sure FID 25 and 31 are both present
2. Add FIX tag 35 = “i”
3. Move the value in FID 8632 to FIX tag 117
4. Concatenate FID 16 + 18 to FIX tag 60
5. Add FIX repeating group 296
6. Add FIX repeating group 295 in repeating group 296
7. Move security id from OMM Header to FIX tag 48 in repeating group 295
8. Add FIX tag 22 as “4” in repeating group 295
9. Move FID 25 to FIX tag 133 in repeating group 295
10. Move FID 31 to FIX tag 135 in repeating group 295
We start with defining the JSON body with empty conditions and actions:
{
"messageRules": [
{
"conditionList": {
"conditions": []
},
"matchActions": {
"actions": []
}
} ]
}
We can add as many “rules” as we like to the JSON, all will be evaluated for each condition that you define. Next add the conditions:
{
"messageRules": [
{
"conditionList": {
"conditions": [
{
"conditionType": "AND",
"conditions": [
{
"conditionType": "PRESENT",
"tagId": 25
},
{
"conditionType": "PRESENT",
"tagId": 31
}
]
}
]
},
"matchActions": {
"actions": []
}
}
]
}
This will check for the existence of FID 25 and 31. If condition is met, the actions we define will be invoked:
{
"messageRules": [
{
"conditionList": {
"conditions": [
{
"conditionType": "AND",
"conditions": [
{
"conditionType": "PRESENT",
"tagId": 25
},
{
"conditionType": "PRESENT",
"tagId": 31
}
]
}
]
},
"matchActions": {
"actions": [
{
"actionType": "ADD",
"destTag": 35,
"tagValue": "i"
},
{
"actionType": "MOVE",
"srcTag": 8632,
"destTag": 117
},
{
"actionType": "TIMESTAMP",
"dateTag": 16,
"timeTag": 18,
"destTag": 60
},
{
"actionType": "REPEATINGGROUP",
"destTag": 296,
"actions": [
{
"actionType": "REPEATINGGROUP",
"destTag": 295,
"actions": [
{
"actionType": "ITEMNAME",
"destTag": 48
},
{
"actionType": "ADD",
"destTag": 22,
"tagValue": "4"
},
{
"actionType": "MOVE",
"srcTag": 25,
"destTag": 133
},
{
"actionType": "MOVE",
"srcTag": 31,
"destTag": 135
}
]
}
]
}
]
},
"notMatchActions": {
"actions": [
{
"actionType": "REJECT"
}
]
}
}
]
}
The actions will set FIX tag 35 = i, move FID 8632 to FIX 117, create FIX tag 60 from FID 16 + 18, create the nested repeating groups, and add FIX tag 48 as security id from the OMM header named ITEMNAME, set FIX tag 22 = 4, move FID 25 to FIX 133 and move FID 31 to FIX 135.
The notMatchActions will cause an OMM NACK to be generated back to the sender if the conditions are not met.
The rules file is specified with the --rulesfile parameter to the start script with. A different rules file should be defined for each APA destination and the appropriate loaded at startup.
Custom RDM Dictionaries
We have included the RDM dictionaries, however if you have customized your own you can specify the location using the ---postdictionary and --postenums options at startup.
OMM Post ACK/NACK
If the message is successfully accepted and transformed to FIX an OMM ACK message will be returned. This does not mean that the APA successfully accepted the FIX message, only that it was converted. If the message was not converted a NACK will be returned.
Logs
All outbound FIX messages to APAs and inbound from APAs are logged in standard FIX logs, along with all other FIX events. All FIX messages are also logged in JSON formatted logs, which then can easily be loaded to a data storage application such as Elasticsearch. The FIX log directory and JSON log directory are each specified at startup using --filelog an --json options.
JMX Management
The QuickFIX/J engine supports standard JMX commands for FIX engine management. You can use any JMX compatible application, including JConsole. The default JMX port is 6998 and you can access it using JConsole by running jconsole 10.89.5.230:6998. QuickFIX/J commands are all under the org.quickfix MBean. See http://www.quickfixj.org/quickfixj/usermanual/1.6.3/usage/jmx.html for more info.
Sample JMX JConsole command screen
Running with Docker
The OMM to FIX Gateway has been built and tested on Docker and will be distributed via DockerHub. Docker is a software container platform that allows us to ship the entire E3PA environment in one package that can be run on any Docker-enabled host. The environment contains the operating system, Java version, etc., any libraries and settings. For more info on Docker see https://www.docker.com/what-docker.
To install the OMM to FIX Gateway you need build the Docker image as described earlier using “docker build” command. To list the image(s) installed, including the one you just created, run “docker images” which will display something like::
REPOSITORY TAG IMAGE ID CREATED SIZE
e3pa latest 2d94f587a47a 2 hours ago 704 MB
If you wish to install the image on a machine different from where you built it you must save the image on the build machine by running “docker save -o e3pa.tar e3pa”, then copying the tar file to the host where you want to run the image and then run “docker load -i e3pa.tar”. This will load and create the image.
Use the docker run command to start an instance, known as a container, of the OMM to FIX. You can use all the same parameters outlined above. The logs and JSON directories should be mapped using the -v Docker option and the ADS and JMX port mapped using the -p Docker option.
docker run --network=host --name E3PAGateway e3pa:latest
Docker options:
-p <host ADS port>:14003
-p <host JXM port>:6998
-v <host log directory>:/var/log/APAGateway
-v <host JSON rules directory>:/etc/APAGateway/rules
refinitiv/e3pa-gateway:latest
OMM to FIX gateway options:
--server
-a <trep user id>
-i <trep service id>
--service <trep service name>
-s <sender comp id>
-t <target comp id>
-e <remote FIX host>
-g <remote FIX post>
-k <FIX version>
(additional options above)
A sample Docker run command might appear as:
docker run --network=host --name APAGateway -p 14003:14003 -p 6998:6998 -v /home/apauser/APA/logs:/var/log/APAGateway -v /home/apauser/APA/config:/etc/APAGateway/rules refinitiv/apa:latest --server -a rmds -i 256 --service AUTEX_APA -s SENDER_COMP_ID -t TARGET_COMP_ID -e 192.0.0.1 -g 7000 -k FIXT.1.1
The above command maps ports 14003 and 6998 from the host to the container, and the host file locations of the logs and the JSON config files under the user’s /home/apauser directory. This allows the user to use whichever ports and file locations they want on their local host without reconfiguring the Docker container.
Message Flow Overview