Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Build a FIX engine using Quickfix/J and Quarkus

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

    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

    • Every layer counts: Defense in depth for AI agents with Red Hat AI

    • Fun in the RUN instruction: Why container builds with distroless images can surprise you

    • Trusted software factory: Building trust in the agentic AI era

    • Build a zero trust AI pipeline with OpenShift and RHEL CVMs

    • Red Hat Hardened Images: Top 5 benefits for software developers

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    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
    © 2026 Red Hat

    Red Hat legal and privacy links

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

    Chat Support

    Please log in with your Red Hat account to access chat support.