This project is a Spring Boot Starter for QuickFIX/J messaging engine for the FIX protocol. It simplifies the configuration required to create and start an Initiator or Acceptor, and handles the lifecycle of the Connector.
To use the QuickFIX/J Server or QuickFIX/J Client you have to add the QuickFIX/J Spring Boot Starter dependency in your project.
<dependency>
<groupId>io.allune</groupId>
<artifactId>quickfixj-spring-boot-starter</artifactId>
<version>2.10.1</version>
</dependency>
To enable the actuator endpoints you will also have to add the QuickFIX/J Spring Boot Actuator dependency.
<dependency>
<groupId>io.allune</groupId>
<artifactId>quickfixj-spring-boot-actuator</artifactId>
<version>2.10.1</version>
</dependency>
The @EnableQuickFixJServer
will auto configure a QuickFIX/J Server:
@EnableQuickFixJServer
@SpringBootApplication
public class AppServer {
public static void main(String[] args) {
SpringApplication.run(AppServer.class, args);
}
}
The configuration can be done in the application.properties / application.yml.
quickfixj.server.config=classpath:quickfixj-server.cfg
quickfixj:
server:
config: classpath:quickfixj-server.cfg
Additionally you need to add a quickfixj-server.cfg file to configure the FIX sessions. The configuration is resolved using the following approach:
-
By a QuickFIX/J acceptor configuration string defined by the
quickfixj.server.configString
property -
By the presence of a
quickfix.SessionSettings
bean namedserverSessionSettings
-
By a configuration file defined by the
quickfixj.server.config
property -
By the presence of the
quickfixj.server.config
system property -
By a
quickfixj-server.cfg
in the working directory or at the root of the classpath
quickfixj.server.config=classpath:quickfixj-server.cfg # location of the quickfixj acceptor configuration file
quickfixj.server.auto-startup=true # whether to auto-connect to the remote endpoint at start up (default: `true`)
quickfixj.server.force-disconnect=false # whether logged on sessions should be disconnected forcibly when the connector is stopped (default: `false`)
quickfixj.server.phase=0 # phase in which this connection manager should be started and stopped (default: `Integer.MAX_VALUE`)
quickfixj.server.jmx-enabled=true # whether to register the jmx mbeans for the acceptor (default: `false`)
quickfixj.server.message-store-factory=memory # [cachedfile,file,jdbc,memory,noop,sleepycat] (default: `memory`)
quickfixj.server.log-factory=screen # [compositelog,file,jdbc,slf4j,screen] (default: `screen`)
quickfixj.server.concurrent.enabled=true # whether to use a simple SocketAcceptor or a ThreadedSocketAcceptor (default: `false` - uses `SocketAcceptor`)
quickfixj.server.concurrent.useDefaultExecutorFactory=true # whether to use a default ExecutorFactory to create the SocketAcceptor (default: `false`)
quickfixj.server.concurrent.queueCapacity=Integer.MAX_VALUE # when using the default ExecutorFactory, the Executor's queue capacity (default: `Integer.MAX_VALUE`)
quickfixj.server.concurrent.corePoolSize=8 # when using the default ExecutorFactory, the Executor's core pool size (default: `8`)
quickfixj.server.concurrent.maxPoolSize=Integer.MAX_VALUE # when using the default ExecutorFactory, the Executor's max pool size (default: `Integer.MAX_VALUE`)
quickfixj.server.concurrent.allowCoreThreadTimeOut=true # when using the default ExecutorFactory, whether to allow core thread timeout on the Executor (default: `true`)
quickfixj.server.concurrent.keepAliveSeconds=60 # when using the default ExecutorFactory, the Executor's keep alive in seconds (default: `60`)
quickfixj.server.concurrent.waitForTasksToCompleteOnShutdown=false # when using the default ExecutorFactory, whether to wait for tasks to complete on shutdown on the Executor (default: `false`)
quickfixj.server.concurrent.awaitTerminationSeconds=0 # when using the default ExecutorFactory, the Executor's await termination in seconds (default: `0`)
quickfixj.server.concurrent.threadNamePrefix="QuickFixJ Spring Boot Starter thread-" # when using the default ExecutorFactory, the Executor's thread name prefix (default: `QuickFixJ Spring Boot Starter thread-`)
quickfixj:
server:
config: classpath:quickfixj-server.cfg
auto-startup: true
force-disconnect: false
phase: 0
jmx-enabled: true
concurrent:
enabled: true
useDefaultExecutorFactory: true
queueCapacity: Integer.MAX_VALUE
corePoolSize: 8
maxPoolSize: Integer.MAX_VALUE
allowCoreThreadTimeOut: true
keepAliveSeconds: 60
waitForTasksToCompleteOnShutdown: false
awaitTerminationMillis: 0
threadNamePrefix: "QuickFixJ Spring Boot Starter thread-"
message-store-factory: memory
log-factory: screen
Using the quickfixj.server.configString
property:
quickfixj.server.configString=[default] \r\n\
FileStorePath=target/data/executor \r\n\
ConnectionType=acceptor \r\n\
StartTime=00:00:00 \r\n\
EndTime=00:00:00 \r\n\
HeartBtInt=30 \r\n\
ValidOrderTypes=1,2,F \r\n\
SenderCompID=EXEC \r\n\
TargetCompID=BANZAI \r\n\
UseDataDictionary=Y \r\n\
DefaultMarketPrice=12.30 \r\n\
FileLogPath=logs-server \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.0 \r\n\
SocketAcceptPort=9876 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.1 \r\n\
SocketAcceptPort=9877 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.2 \r\n\
SocketAcceptPort=9878 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.3 \r\n\
SocketAcceptPort=9879 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.4 \r\n\
SocketAcceptPort=9880 \r\n\
\r\n\
[session] \r\n\
BeginString=FIXT.1.1 \r\n\
DefaultApplVerID=FIX.5.0SP2 \r\n\
SocketAcceptPort=9881
quickfixj:
server:
configString: |
[default]
FileStorePath=target/data/executor
ConnectionType=acceptor
StartTime=00:00:00
EndTime=00:00:00
HeartBtInt=30
ValidOrderTypes=1,2,F
SenderCompID=EXEC
TargetCompID=BANZAI
UseDataDictionary=Y
DefaultMarketPrice=12.30
FileLogPath=logs-server
[session]
BeginString=FIX.4.0
SocketAcceptPort=9876
[session]
BeginString=FIX.4.1
SocketAcceptPort=9877
[session]
BeginString=FIX.4.2
SocketAcceptPort=9878
[session]
BeginString=FIX.4.3
SocketAcceptPort=9879
[session]
BeginString=FIX.4.4
SocketAcceptPort=9880
[session]
BeginString=FIXT.1.1
DefaultApplVerID=FIX.5.0SP2
SocketAcceptPort=9881
management.endpoint.quickfixjserver.enabled=true # whether the endpoint is enabled or not
management.endpoints.web.exposure.include=quickfixjserver # whether the endpoint will be exposed
management:
endpoint:
quickfixjserver:
enabled: true
endpoints:
web:
exposure:
include: quickfixjserver
Example usage:
http://localhost:8081/actuator/quickfixjserver
{
"FIX.4.2:EXEC->BANZAI": {
"SenderCompID": "EXEC",
"StartTime": "00:00:00",
"DefaultMarketPrice": "12.30",
"ValidOrderTypes": "1,2,F",
"ConnectionType": "acceptor",
"EndTime": "00:00:00",
"BeginString": "FIX.4.2",
"SocketAcceptPort": "9878",
"TargetCompID": "BANZAI",
"SenderCompID": "EXEC",
"HeartBtInt": "30",
"BeginString": "FIX.4.2",
"TargetCompID": "BANZAI",
"FileStorePath": "target/data/executor",
"UseDataDictionary": "Y"
},
"FIX.4.1:EXEC->BANZAI": {
"SenderCompID": "EXEC",
"StartTime": "00:00:00",
"DefaultMarketPrice": "12.30",
"ValidOrderTypes": "1,2,F",
"ConnectionType": "acceptor",
"EndTime": "00:00:00",
"BeginString": "FIX.4.1",
"SocketAcceptPort": "9877",
"TargetCompID": "BANZAI",
"SenderCompID": "EXEC",
"HeartBtInt": "30",
"BeginString": "FIX.4.1",
"TargetCompID": "BANZAI",
"FileStorePath": "target/data/executor",
"UseDataDictionary": "Y"
}
}
The @EnableQuickFixJClient
will auto configure a QuickFIX/J Client:
@EnableQuickFixJClient
@SpringBootApplication
public class AppClient {
public static void main(String[] args) {
SpringApplication.run(AppClient.class, args);
}
}
The configuration can be done in the application.properties / application.yml.
quickfixj.client.config=classpath:quickfixj-client.cfg
quickfixj:
client:
config: classpath:quickfixj-client.cfg
Additionally you need to add a quickfixj-client.cfg file to configure the FIX sessions. The configuration is resolved using the following approach:
-
By a QuickFIX/J initiator configuration string defined by the
quickfixj.client.configString
property -
By the presence of a
quickfix.SessionSettings
bean namedclientSessionSettings
-
By a configuration file defined by the
quickfixj.client.config
property -
By the presence of the
quickfixj.client.config
system property -
By a
quickfixj-client.cfg
in the working directory or at the root of the classpath
quickfixj.client.config=classpath:quickfixj-client.cfg # location of the quickfixj initiator
quickfixj.client.auto-startup=true # whether to auto-connect to the remote endpoint at start up (default: `true`)
quickfixj.client.phase=0 # phase in which this connection manager should be started and stopped (default: `Integer.MAX_VALUE`)
quickfixj.client.jmx-enabled=true # whether to register the jmx mbeans for the initiator (default: `false`)
quickfixj.client.message-store-factory=memory # [cachedfile,file,jdbc,memory,noop,sleepycat] (default: `memory`)
quickfixj.client.log-factory=screen # [compositelog,file,jdbc,slf4j,screen] (default: `screen`)
quickfixj.client.concurrent.enabled=true # whether to use a simple SocketInitiator or a ThreadedSocketInitiator (default: `false` - uses `SocketInitiator`)
quickfixj.client.concurrent.useDefaultExecutorFactory=true # whether to use a default ExecutorFactory to create the SocketInitiator (default: `false`)
quickfixj.client.concurrent.queueCapacity=Integer.MAX_VALUE # when using the default ExecutorFactory, the Executor's queue capacity (default: `Integer.MAX_VALUE`)
quickfixj.client.concurrent.corePoolSize=8 # when using the default ExecutorFactory, the Executor's core pool size (default: `8`)
quickfixj.client.concurrent.maxPoolSize=Integer.MAX_VALUE # when using the default ExecutorFactory, the Executor's max pool size (default: `Integer.MAX_VALUE`)
quickfixj.client.concurrent.allowCoreThreadTimeOut=true # when using the default ExecutorFactory, whether to allow core thread timeout on the Executor (default: `true`)
quickfixj.client.concurrent.keepAliveSeconds=60 # when using the default ExecutorFactory, the Executor's keep alive in seconds (default: `60`)
quickfixj.client.concurrent.waitForTasksToCompleteOnShutdown=false # when using the default ExecutorFactory, whether to wait for tasks to complete on shutdown on the Executor (default: `false`)
quickfixj.client.concurrent.awaitTerminationSeconds=0 # when using the default ExecutorFactory, the Executor's await termination in seconds (default: `0`)
quickfixj.client.concurrent.threadNamePrefix="QuickFixJ Spring Boot Starter thread-" # when using the default ExecutorFactory, the Executor's thread name prefix (default: `QuickFixJ Spring Boot Starter thread-`)
quickfixj:
client:
config: classpath:quickfixj-server.cfg
auto-startup: true
force-disconnect: false
phase: 0
jmx-enabled: true
concurrent:
enabled: true
useDefaultExecutorFactory: true
queueCapacity: Integer.MAX_VALUE
corePoolSize: 8
maxPoolSize: Integer.MAX_VALUE
allowCoreThreadTimeOut: true
keepAliveSeconds: 60
waitForTasksToCompleteOnShutdown: false
awaitTerminationMillis: 0
threadNamePrefix: "QuickFixJ Spring Boot Starter thread-"
message-store-factory: memory
log-factory: screen
Using the quickfixj.client.configString
property:
quickfixj.client.configString=[default] \r\n\
FileStorePath=target/data/banzai \r\n\
ConnectionType=initiator \r\n\
SenderCompID=BANZAI \r\n\
TargetCompID=EXEC \r\n\
SocketConnectHost=localhost \r\n\
StartTime=00:00:00 \r\n\
EndTime=00:00:00 \r\n\
HeartBtInt=30 \r\n\
ReconnectInterval=5 \r\n\
FileLogPath=logs-client \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.0 \r\n\
SocketConnectPort=9876 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.1 \r\n\
SocketConnectPort=9877 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.2 \r\n\
SocketConnectPort=9878 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.3 \r\n\
SocketConnectPort=9879 \r\n\
\r\n\
[session] \r\n\
BeginString=FIX.4.4 \r\n\
SocketConnectPort=9880 \r\n\
\r\n\
[session] \r\n\
BeginString=FIXT.1.1 \r\n\
DefaultApplVerID=FIX.5.0SP2 \r\n\
SocketConnectPort=9881
quickfixj:
client:
configString: |
[default]
FileStorePath=target/data/banzai
ConnectionType=initiator
SenderCompID=BANZAI
TargetCompID=EXEC
SocketConnectHost=localhost
StartTime=00:00:00
EndTime=00:00:00
HeartBtInt=30
ReconnectInterval=5
FileLogPath=logs-client
[session]
BeginString=FIX.4.0
SocketConnectPort=9876
[session]
BeginString=FIX.4.1
SocketConnectPort=9877
[session]
BeginString=FIX.4.2
SocketConnectPort=9878
[session]
BeginString=FIX.4.3
SocketConnectPort=9879
[session]
BeginString=FIX.4.4
SocketConnectPort=9880
[session]
BeginString=FIXT.1.1
DefaultApplVerID=FIX.5.0SP2
SocketConnectPort=9881
management.endpoint.quickfixjclient.enabled=true # whether the endpoint is enabled or not
management.endpoints.web.exposure.include=quickfixjclient # whether the endpoint will be exposed
management:
endpoint:
quickfixjclient:
enabled: true
endpoints:
web:
exposure:
include: quickfixjclient
Example usage:
http://localhost:8080/actuator/quickfixjclient
{
"FIXT.1.1:BANZAI->EXEC": {
"SenderCompID": "BANZAI",
"StartTime": "00:00:00",
"ConnectionType": "initiator",
"EndTime": "00:00:00",
"BeginString": "FIXT.1.1",
"ReconnectInterval": "5",
"TargetCompID": "EXEC",
"DefaultApplVerID": "FIX.5.0",
"SocketConnectHost": "localhost",
"SenderCompID": "BANZAI",
"HeartBtInt": "30",
"BeginString": "FIXT.1.1",
"TargetCompID": "EXEC",
"FileStorePath": "target/data/banzai",
"SocketConnectPort": "9881"
},
"FIX.4.2:BANZAI->EXEC": {
"SenderCompID": "BANZAI",
"StartTime": "00:00:00",
"ConnectionType": "initiator",
"EndTime": "00:00:00",
"BeginString": "FIX.4.2",
"ReconnectInterval": "5",
"TargetCompID": "EXEC",
"SocketConnectHost": "localhost",
"SenderCompID": "BANZAI",
"HeartBtInt": "30",
"BeginString": "FIX.4.2",
"TargetCompID": "EXEC",
"FileStorePath": "target/data/banzai",
"SocketConnectPort": "9878"
}
}
The QuickFIX/J Spring Boot Starter provides a default implementation for the quickfixj.Application
interface which publishes the messages received by the Server (Acceptor) and the Client (Initiator) as `ApplicationEvent`s.
If your application is only processing a subset of message types (i.e. toAdmin
, toApp
, onCreate
, etc.) you will need to register an EventListener
for these, with the appropriate message type as the only parameter for the listener method:
@EventListener
public void listenFromAdmin(FromAdmin fromAdmin) {
...
}
@EventListener
public void listenFromApp(FromApp fromApp) {
...
}
@EventListener
public void listenOnCreate(Create create) {
...
}
@EventListener
public void listenOnLogon(Logon logon) {
...
}
@EventListener
public void listenOnLogout(Logout logout) {
...
}
@EventListener
public void listenToAdmin(ToAdmin toAdmin) {
...
}
@EventListener
public void listenToApp(ToApp toApp) {
...
}
In case the EventListener
method throws an exception, this exception will be propagated up the quickfix.Session#next()
method.
Depending on the value of RejectMessageOnUnhandledException
in the quickfixj configuration file, the message will be redelivered or dismissed.
The QuickFixJTemplate
provides a synchronous client to perform requests, exposing a simple, template method API over the QuickFIX/J client.
The QuickFIX/J Spring Boot Starter provides a quickFixJTemplate
bean than can be Autowired
in the application.
@Autowire
private QuickFixJTemplate quickFixJTemplate;
...
SessionID sessionID = serverAcceptor.getSessions().stream()
.filter(sessId ->
sessId.getBeginString().equals(fixVersion) &&
sessId.getTargetCompID().equals(targetId))
.findFirst()
.orElseThrow(RuntimeException::new);
OrderCancelRequest message = new OrderCancelRequest(
new OrigClOrdID("123"),
new ClOrdID("321"),
new Symbol("LNUX"),
new Side(Side.BUY));
quickFixJTemplate.send(message, sessionID);
-
QuickFIX/J Spring Boot Server and Client applications as Docker containers
-
QuickFIX/J Spring Boot Server and Client applications as Docker containers with server failover
-
QuickFIX/J Spring Boot Client application with Event Listeners
-
QuickFIX/J Spring Boot Client application with database message store
-
QuickFIX/J Spring Boot Server application with Dynamic Sessions
-
QuickFIX/J Spring Boot Server application with Event Listeners
-
QuickFIX/J Spring Boot Server application with database message store
The QuickFIX/J Spring Boot Starter is released under version 2.0 of the Apache License.
This code includes software developed by quickfixengine.org.