Skip to main content
Redhat Developers  Logo
  • Products

    Platforms

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat AI
      Red Hat AI
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • View All Red Hat Products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat Developer Hub
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat OpenShift Local
    • Red Hat Developer Sandbox

      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Secure Development & Architectures

      • Security
      • Secure coding
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • Product Documentation
    • API Catalog
    • Legacy Documentation
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

Build a FIX engine using Quickfix/J and Quarkus

February 1, 2022
Stephen Nimmo
Related topics:
Event-DrivenJavaKubernetesQuarkus
Related products:
Red Hat OpenShift

Share:

    If you have spent any time in a trading organization, whether foreign exchange (FX), commodities, or equities, there's a good chance you've encountered the Financial Information eXchange (FIX) protocol. FIX is a socket-based, asynchronous message protocol designed for electronic trading. The protocol is implemented and used across all the major exchanges, such as NYSE, NASDAQ, CME, and ICE. FIX provides an API to broker-dealers and retail customers to obtain security definitions, submit and manage orders, and receive events such as trades.

    This article guides you through the steps to develop a basic application that can exchange financial information over the FIX protocol in a Java application using the QuickFIX/J engine. We'll use Quarkus to gain access to the many conveniences this framework offers.

    What is the FIX protocol?

    The power of the FIX protocol comes from its standardization and size. FIX messages are defined as groupings of tag=value pairs, where the tags are a standard set of integers corresponding to valid types of fields. For instance, the field identifying the message type has tag 35. Fields are separated by a control character called the Start of Heading or <SOH> character, and its value is 1.

    The FIX message is broken into three parts: header, body, and trailer. The header contains metadata about the message, including what version of the protocol is being used, what type of message it is, routing information, its sequence number within the current FIX session, and the length of the message. The body contains the message contents based on the header's message type. The trailer contains a checksum for the message and, optionally, an electronic signature.

    Here's an example FIX NewOrderSingle message with the SOH character replaced with a pipe character for readability:

    8=FIX.4.4|9=148|35=D|34=1080|49=TESTBUY1|52=20180920-18:14:19.508|56=TESTSELL1|11=636730640278898634|15=USD|21=2|38=7000|40=1|54=1|55=MSFT|60=20180920-18:14:19.492|10=092

    A FIX protocol implementation is typically defined as a FIX engine. The FIX engine can be written in any language and provides the building blocks that are required to process messages. These include establishing the transport protocol (typically TCP), creating FIX sessions, and serializing and deserializing messages. A FIX engine can also provide other features, such as session state management, logging, failover protocols, and session scheduling.

    Although the protocol itself is bidirectional, each FIX connection must be designated as either an initiator or an acceptor. On an initiator connection, the engine reaches out to another FIX engine using an IP address and port. On an acceptor connection, the engine simply defines a port on which connections are accepted. Within the trading industry, the exchanges usually define their FIX engines as acceptors, allowing their trading counterparties to define their connections as initiators.

    Note: Learn more about the FIX specification and related standards.

    The QuickFIX/J engine

    One of the most popular FIX engine implementations is the QuickFIX family. The QuickFIX engine is available in a myriad of languages, including C++, Python, Ruby, .NET, and Go. For this project, we will use the Java implementation, known as QuickFIX/J.

    Much of a QuickFIX/J engine implementation happens in its configuration file. Here's a bare-bones example of a configuration for two different sessions:

    [SESSION]
    ConnectionType=acceptor
    BeginString=FIX.4.4
    SenderCompID=TESTSEND1
    TargetCompID=TESTTARGET1
    SocketAcceptPort=10000
    StartTime=00:00:00
    EndTime=00:00:00
    
    [SESSION]
    ConnectionType=initiator
    BeginString=FIX.4.2
    SenderCompID=TESTSEND2
    TargetCompID=TESTTARGET2
    SocketConnectHost=127.0.0.1
    SocketConnectPort=1234
    StartTime=08:30:00
    EndTime=04:30:00
    TimeZone=America/New_York
    HeartBtInt=30

    The first session is an acceptor and uses acceptor configuration options. When the engine starts, it opens port 10000 and begins listening for new connections. It accepts connections only from an initiator that specifies the protocol as version FIX.4.4. The initiator must also provide the correct SenderCompId and TargetCompId information, which is the inverse of the defined session. Another ubiquitous part of a session definition is scheduling information (the StartTime and EndTime fields). In this example, the acceptor always accepts connections regardless of the time of day.

    The second session definition is an initiator and uses initiator configuration options. When the engine starts, it attempts to connect to another FIX engine based on the supplied SocketConnectHost and SocketConnectPort. Again, the FIX version, SenderCompID, and TargetCompID must match for the acceptor engine to allow the connection to proceed. The initiator example is a bit different, in this case, because we have set some additional restrictions on when the session can be active by providing the StartTime, EndTime, and TimeZone for the connection. If the engine is running in that time window, it attempts to establish and maintain a connection.

    Configuring QuickFIX/J

    The QuickFIX/J engine offers building blocks, which you as a developer must configure. Options include how your implementation will store messages, log messages, and serialize and deserialize messages. Table 1 shows some of the available options.

    Table 1. QuickFIX/J's building blocks and configuration options.
    Building blockOptions
    MessageStoreFactoryChoose from CachedFileStoreFactory, FileStoreFactory, JdbcStoreFactory, or MemoryStoreFactory.
    LogFactoryChoose from FileLogFactory, JdbcLogFactory, SLF4JLogFactory, or ConsoleLogFactory.
    MessageFactorySelect the DefaultMessageFactory or MessageFactory for the given FIX version.
    ApplicationThe interface for message flows. Implement the Application interface and handle the incoming and outgoing message events.

    The application reads the configuration file and builds a SessionSettings object. You then define the building blocks and have the option to pass the configuration to each of the factories using the SessionSettings object. Once the building blocks are established, you can create connectors using the building blocks as constructor parameters. The following is a basic example found on the QuickFIX/J website:

    import quickfix.*;
    import java.io.FileInputStream;
    
    public class MyClass {
    
      public static void main(String args[]) throws Exception {
        if (args.length != 1) return;
        String fileName = args[0];
    
        // FooApplication is your class that implements the Application interface
        Application application = new FooApplication();
    
        SessionSettings settings = new SessionSettings(new FileInputStream(fileName));
        MessageStoreFactory storeFactory = new FileStoreFactory(settings);
        LogFactory logFactory = new FileLogFactory(settings);
        MessageFactory messageFactory = new DefaultMessageFactory();
        Acceptor acceptor = new SocketAcceptor
          (application, storeFactory, settings, logFactory, messageFactory);
        acceptor.start();
        // while(condition == true) { do something; }
        acceptor.stop();
      }
    
    }

    Running QuickFIX/J in Quarkus

    With Quarkus, developers can now define the QuickFIX/J building blocks using Contexts and Dependency Injection (CDI). In this section, we'll develop a simple Quarkus application that runs QuickFIX/J. The sample code can be found in my GitHub repository. See the Quarkus website for additional guidelines for creating your first Quarkus application.

    To get started, let's create a new Quarkus project using the quarkus-maven-plugin:

    $ mvn io.quarkus.platform:quarkus-maven-plugin:2.6.1.Final:create \
        -DprojectGroupId=com.redhat.demo \
        -DprojectArtifactId=quarkus-quickfixj \
        -DclassName="com.redhat.demo.qfj.SessionResource" \
        -Dpath="/sessions"
    $ cd quarkus-quickfixj

    This command creates a simple Quarkus Maven project with the Quarkus RESTEasy extension and demo code. After importing the project into your favorite IDE, you can add the provider definitions for your building blocks.

    To keep things simple, we will implement our FIX engine with a few easy-to-configure factory settings: MemoryStoreFactory, ScreenLogFactory, and DefaultMessageFactory. Let's add the Maven dependency for the QuickFIX/J artifact. The quickfix-all contains all of the artifacts for the project, including the core engine and the message structures for all FIX versions:

    <dependency>
        <groupId>org.quickfixj</groupId>
        <artifactId>quickfixj-all</artifactId>
        <version>2.3.1</version>
    </dependency>

    After adding the dependency, define the necessary configurations. First, go to the application.properties file and add a value for the location of the file containing the SessionSettings:

    quickfixj.sessionSettingsPath=quickfixj.settings

    Then, add a very basic settings file in the src/main/resources directory:

    [SESSION]
    ConnectionType=acceptor
    BeginString=FIX.4.4
    SenderCompID=TESTSEND
    TargetCompID=TESTTARGET
    SocketAcceptPort=10000
    StartTime=00:00:00
    EndTime=00:00:00
    
    [SESSION]
    ConnectionType=initiator
    BeginString=FIX.4.4
    SenderCompID=TESTTARGET
    TargetCompID=TESTSEND
    SocketConnectPort=1234
    SocketConnectHost=127.0.0.1
    StartTime=00:00:00
    EndTime=00:00:00
    HeartBtInt=30

    Now, create the producer class, which will create the building blocks for the FIX engine:

    package com.redhat.demo.qfj;
    
    import org.eclipse.microprofile.config.inject.ConfigProperty;
    import quickfix.*;
    
    import javax.enterprise.inject.Produces;
    
    public class QuickfixjComponentProducer {
    
        @Produces
        public SessionSettings create(@ConfigProperty(name = "quickfixj.sessionSettingsPath") String sessionSettingsPath) throws ConfigError {
            return new SessionSettings(getClass().getClassLoader().getResource(sessionSettingsPath).getFile());
        }
    
        @Produces
        public MessageStoreFactory messageStoreFactory(SessionSettings sessionSettings) {
            return new MemoryStoreFactory();
        }
    
        @Produces
        public LogFactory logFactory(SessionSettings sessionSettings) {
            return new ScreenLogFactory();
        }
    
        @Produces
        public MessageFactory messageFactory(SessionSettings sessionSettings) {
            return new DefaultMessageFactory();
        }
    
        @Produces
        public Application application() {
            return new ApplicationAdapter();
        }
    
    }

    There are a few things to note about the code:

    • To provide the configuration file, we will simply embed it in the classpath. In a production example, you should probably read the configuration file from a filesystem.
    • We are passing the SessionSettings object into each of the producer methods for the components even though we don't actually need them. However, in a production example, the SessionSettings will be needed for the components, because it contains the properties needed.
    • We implement the Application interface using the ApplicationAdapter, which is an empty implementation of the interface. This interface is where the developer customizes how the message flows should be handled.

    Now that the building blocks are present, you can use them to develop the rest of the FIX engine:

    package com.redhat.demo.qfj;
    
    import io.quarkus.runtime.ShutdownEvent;
    import io.quarkus.runtime.StartupEvent;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import quickfix.*;
    
    import javax.enterprise.context.ApplicationScoped;
    import javax.enterprise.event.Observes;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    @ApplicationScoped
    public class QuickfixjEngine {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(QuickfixjEngine.class);
    
        private final SessionSettings sessionSettings;
        private final MessageStoreFactory messageStoreFactory;
        private final LogFactory logFactory;
        private final MessageFactory messageFactory;
        private final Application application;
    
        private Set<Connector> connectorSet = new HashSet<>();
    
        public QuickfixjEngine(SessionSettings sessionSettings, MessageStoreFactory messageStoreFactory, LogFactory logFactory,
                               MessageFactory messageFactory, Application application) throws ConfigError {
            this.sessionSettings = sessionSettings;
            this.messageStoreFactory = messageStoreFactory;
            this.logFactory = logFactory;
            this.messageFactory = messageFactory;
            this.application = application;
        }
    
        void onStartupEvent(@Observes StartupEvent event) {
            LOGGER.info("The QuickfixjService is starting...");
            try {
                Connector acceptorConnector = new SocketAcceptor(application, messageStoreFactory, sessionSettings, logFactory, messageFactory);
                acceptorConnector.start();
                Connector initiatorConnector = new SocketInitiator(application, messageStoreFactory, sessionSettings, logFactory, messageFactory);
                initiatorConnector.start();
                connectorSet.addAll(List.of(acceptorConnector, initiatorConnector));
                LOGGER.debug("All connectors are started...");
            } catch (ConfigError e) {
                //TODO Handle error
                throw new RuntimeException(e);
            }
        }
    
        void onShutdownEvent(@Observes ShutdownEvent event) {
            LOGGER.info("The QuickfixjService is stopping...");
            connectorSet.forEach(Connector::stop);
        }
    
    }

    Note the following:

    • We are using Quarkus application lifecycle events to start and stop the acceptor and initiator connections. Remember that the connection's start and stop are independent of the connection's schedule. If the FIX sessions have a particular schedule, the connections will open and close per the schedule but will still remain as "RUNNING" in the FIX engine context.
    • We are also collecting the acceptor and initiator connections, and keeping track of them in a local Set, which allows the connections to be stopped gracefully on normal application termination.

    Benefits of using Quarkus with QuickFIX/J

    As demonstrated in this article, the basic FIX engine doesn't need anything other than the QuickFIX/J artifacts and a JVM to run. However, by embedding the FIX engine into the Quarkus runtime, you can quickly and easily build the additional components that most FIX engines need to provide business value. You can:

    • Extend capabilities for session management by adding a REST API to manage the sessions from either a user interface or any operational dashboards.
    • Quickly add messaging infrastructure to the Application implementation using Quarkus extensions such as Apache Kafka integration or AMQP.
    • Easily add metrics and observability to the engine using Micrometer and expose application metrics to Prometheus.
    • Add health checks using SmallRye Health.

    In short, by plugging the QuickFIX/J FIX engine into the Quarkus runtime, you can supercharge development and reimagine the ways to implement electronic trading applications.

    Conclusion

    This article introduced the FIX protocol and showed you how to configure the building blocks of a FIX engine using QuickFIX/J. We then developed a Quarkus application with an embedded FIX engine.

    Last updated: May 8, 2024

    Related Posts

    • Choosing the right asynchronous-messaging infrastructure for the job

    • Create your first Quarkus project with Eclipse IDE (Red Hat CodeReady Studio)

    • Visualize your Apache Kafka Streams using the Quarkus Dev UI

    Recent Posts

    • Why some agentic AI developers are moving code from Python to Rust

    • Confidential VMs: The core of confidential containers

    • Benchmarking with GuideLLM in air-gapped OpenShift clusters

    • Run Qwen3-Next on vLLM with Red Hat AI: A step-by-step guide

    • How to implement observability with Python and Llama Stack

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2025 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue