Quickfixj Hello World (WebSocket Initiator-Acceptor Trader/OMS.Broker is initiator & Exchange is acceptor)
Quickfixj provides a engine which is using fix protocol. I will create a simple application using quickfixj.
Even if we create a small application, it is good to give overall design picture. Please see the below. We will have 2 clients. They will communicate via fix protocol using quickfixj engine.

I will follow the steps below:
* Creating java application
* Add quickfixj dependency to application
* Implement quickfixj.Application
* Design fix messages (which fix message will be used and which fields will be included)
* We will have 2 different quickfix engine running (Client1 and Client2)
Creating Java Project
I will create the following project structure:
→ quickfixj-helloworld
— →common
— →client1
— →client2
In order to make a parent java project, use the following command.
$ mvn archetype:generate -DgroupId=com.onrkrdmn -DartifactId=quickfixj-helloworld
This will generate a module. But we want to make this parent project. Therefore, we need to update packaging strategy in pom.xml as in the following to achieve this.
<packaging>pom</packaging>
Also, remove src/ folder from parent.
rm -r ordermatch/src
Make sure that build is fine
$ cd quickfixj-helloworld/
$ mvn clean install
We created parent project. Now, we need sub projects. Lets start with common. This will include shared codes between clients.
$ cd quickfixj-helloworld/
mvn archetype:generate -DgroupId=com.onrkrdmn -DartifactId=common
We are ready to import the project into IDE, my favorite one is intellij :)
First of all, lets configure log4j. Add the following log4j dependency to common/pom.xml
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>Create log4j.properties file under common/src/main/resource (if there is no resource directory, you need to create it). It can look like below
# Root logger option
log4j.rootLogger=DEBUG, stdout
# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%nNow we need to add quickfixj dependency to our project. I will add quickfixj-all. This includes standart fix messages for different versions (from 4.0 to 5)
In order to run fix engine, we need to implement fix Application as in the following.
package com.onrkrdmn;
import org.apache.log4j.Logger;
import quickfix.*;
public class FixApplicationImpl implements Application {
private static final Logger LOGGER = Logger.getLogger(FixApplicationImpl.class);
@Override
public void onCreate(SessionID sessionID) {
}
@Override
public void onLogon(SessionID sessionID) {
}
@Override
public void onLogout(SessionID sessionID) {
}
@Override
public void toAdmin(Message message, SessionID sessionID) {
}
@Override
public void fromAdmin(Message message, SessionID sessionID) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon {
}
@Override
public void toApp(Message message, SessionID sessionID) throws DoNotSend {
}
@Override
public void fromApp(Message message, SessionID sessionID) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {
}
}I will create a scheduler to send hello world in a time interval.
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
public FixApplicationImpl() {
scheduledExecutorService.scheduleAtFixedRate(() -> sendHelloWorld(), 5, 5, TimeUnit.SECONDS);
}We can create sendHelloWorld method as in the following, please notice that we check first if session is logged on.
private void sendHelloWorld() {
if (isLoggedOn()) {
QuoteRequest quoteRequest = new QuoteRequest();
quoteRequest.setString(Text.FIELD, "Hello World");
defaultSession.send(quoteRequest);
} else {
LOGGER.info("session is not logged in, message will not send");
}
}private boolean isLoggedOn() {
return defaultSession != null && defaultSession.isLoggedOn();
}
When session logged on, onLogon method will be called. We can just keep default session in memory in order to send message.
@Override
public void onLogon(SessionID sessionID) {
defaultSession = Session.lookupSession(sessionID);
}Fix application is ready. Now we can set up our first client.
$ cd quickfixj-helloworld/
mvn archetype:generate -DgroupId=com.onrkrdmn -DartifactId=client1
We will set Client1 as acceptor. Having only one main class will be enough.
package com.onrkrdmn;
import quickfix.*;
import java.io.InputStream;
public class Client1App {
public static void main(String[] args) throws ConfigError {
Application fixApplication = new FixApplicationImpl();
Connector connector = createConnector(fixApplication, Client1App.class.getClassLoader().getResourceAsStream("fixsession_acceptor.conf"));
connector.start();
}
private static Connector createConnector(Application fixApp, InputStream acceptorConfig) throws ConfigError {
SessionSettings settings = new SessionSettings(acceptorConfig);
MessageStoreFactory storeFactory = new FileStoreFactory(settings);
LogFactory logFactory = new FileLogFactory(settings);
MessageFactory messageFactory = new DefaultMessageFactory();
return new SocketAcceptor(fixApp, storeFactory, settings, logFactory, messageFactory);
}
}I configured the following session conf file under resource.
[default]
FileStorePath=target/data/acceptor_store
FileLogPath=target/data/acceptor_log
ConnectionType=acceptor
StartTime=00:00:00
EndTime=00:00:00
HeartBtInt=30
ResetOnLogon=Y
ResetOnLogout=Y
ResetOnDisconnect=Y
SocketAcceptPort=9876
UseDataDictionary=N
BeginString=FIX.4.4
SendRedundantResendRequests=N
[session]
SenderCompID=CLIENT1
TargetCompID=CLIENT2Try to run this main method. It should be run but of course will not be able to send an message since session is not logged on.
Let’s create second client as initiator.
mvn archetype:generate -DgroupId=com.onrkrdmn -DartifactId=client2
Main starter class will be almost same as Client1 but only difference we need to create “SocketInitiator” instead of “SocketAcceptor”.
package com.onrkrdmn;
import quickfix.*;
import java.io.InputStream;
public class Client2App {
public static void main(String[] args) throws ConfigError {
Application fixApplication = new FixApplicationImpl();
Connector connector = createConnector(fixApplication, Client2App.class.getClassLoader().getResourceAsStream("fixsession_initiator.conf"));
connector.start();
}
private static Connector createConnector(Application fixApp, InputStream acceptorConfig) throws ConfigError {
SessionSettings settings = new SessionSettings(acceptorConfig);
MessageStoreFactory storeFactory = new FileStoreFactory(settings);
LogFactory logFactory = new FileLogFactory(settings);
MessageFactory messageFactory = new DefaultMessageFactory();
return new SocketInitiator(fixApp, storeFactory, settings, logFactory, messageFactory);
}
}Session config file as in the following:
[default]
FileStorePath=target/data/initiator_store
FileLogPath=target/data/initiator_log
ConnectionType=initiator
StartTime=00:00:00
EndTime=00:00:00
HeartBtInt=30
SocketConnectPort=9876
SocketConnectHost=localhost
UseDataDictionary=N
ResetOnLogon=Y
ResetOnLogout=Y
ResetOnDisconnect=Y
BeginString=FIX.4.4
SendRedundantResendRequests=N
[session]
TargetCompID=CLIENT1
SenderCompID=CLIENT2When you run these two clients, you will see the communication. See the example output from client1:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
2020-07-13 22:47:36 INFO FixApplicationImpl:63 - session is not logged in, message will not send
2020-07-13 22:47:37 INFO FixApplicationImpl:28 - Session is logged on
2020-07-13 22:47:39 INFO FixApplicationImpl:54 - Message received:8=FIX.4.49=7235=R34=249=CLIENT252=20200713-20:47:39.53356=CLIENT158=Hello World10=163
2020-07-13 22:47:41 INFO FixApplicationImpl:49 - Message is being sent:8=FIX.4.49=7235=R34=249=CLIENT152=20200713-20:47:41.17656=CLIENT258=Hello World10=159
2020-07-13 22:47:44 INFO FixApplicationImpl:54 - Message received:8=FIX.4.49=7235=R34=349=CLIENT252=20200713-20:47:44.53056=CLIENT158=Hello World10=157
2020-07-13 22:47:46 INFO FixApplicationImpl:49 - Message is being sent:8=FIX.4.49=7235=R34=349=CLIENT152=20200713-20:47:46.17656=CLIENT258=Hello World10=165
2020-07-13 22:47:49 INFO FixApplicationImpl:54 - Message received:8=FIX.4.49=7235=R34=449=CLIENT252=20200713-20:47:49.52956=CLIENT158=Hello World10=171source code -> https://github.com/onurkaraduman/examples/tree/master/java-examples/quickfixj/quickfixj-helloworld
Comments
Post a Comment