Skip to content

paicoretech/fix-http-server

Repository files navigation

FIX Gateway HTTP Server

A Spring Boot service that translates REST HTTP calls into FIX 4.4 protocol messages and back. It acts as a bridge so that applications with no knowledge of FIX can participate in FX trading workflows by sending simple JSON HTTP requests.

sequenceDiagram
    participant Client as Client Application
    participant Gateway as FIX Gateway
    participant Counterparty as FIX Counterparty

    Note over Client,Counterparty: Quote Request Flow

    Client->>Gateway: POST /quote
    Gateway->>Counterparty: QuoteRequest (FIX R)
    Counterparty-->>Gateway: Quote (FIX S)
    Gateway-->>Client: JSON Quote

    Note over Client,Counterparty: Order Execution Flow

    Client->>Gateway: POST /order
    Gateway->>Counterparty: NewOrderSingle (FIX D)
    Counterparty-->>Gateway: ExecutionReport (FIX 8)
    Gateway-->>Client: JSON Fill
Loading

Table of Contents

  1. Features
  2. Requirements
  3. Quick Start
  4. Configuration
  5. API Reference
  6. Running with Docker
  7. Local Development (Mock Simulator)
  8. Architecture
  9. Contributing
  10. License

Features

  • Three REST endpoints covering the full RFQ trading lifecycle:
    • POST /quote — request an exchange rate quote (no trade execution)
    • POST /order — execute a trade against a previously obtained quote
    • POST /quote-order — request a quote and execute immediately in one call
  • FIX 4.4 via QuickFIX/J with dual concurrent sessions (market data + trading)
  • PostgreSQL persistence — every quote request and execution report is stored
  • API key authentication — configurable multi-key support via X-API-Key header
  • Reactive stack — Spring WebFlux with virtual threads (JDK 21)
  • Configurable weekly sequence reset — keeps FIX sequence numbers in sync with the counterparty

Requirements

Dependency Version
JDK 21
Maven 3.9+
PostgreSQL 13+

Quick Start

1. Clone and build

git clone https://github.com/your-org/fix-http-server.git
cd fix-http-server
mvn clean package -DskipTests

2. Provide configuration

Copy the example files into a secrets/ directory (gitignored):

mkdir secrets
cp secrets.template/application.properties/application.properties.example.txt secrets/application.properties
cp secrets.template/quickfixj.cfg.example.txt secrets/quickfixj.cfg

Edit both files — at minimum set your database credentials and API key:

# secrets/application.properties
spring.datasource.password=your_db_password
api.security.keys=your-api-key
# secrets/quickfixj.cfg — set your FIX counterparty details
[SESSION]
SenderCompID=YOUR.SENDER.ID
TargetCompID=COUNTERPARTY.TARGET.ID
SocketConnectHost=fix.counterparty.example.com
SocketConnectPort=9999

3. Create the database

CREATE DATABASE fix_gateway;

4. Run

java \
  -Dspring.config.location=classpath:application.properties,file:secrets/application.properties \
  -Dquickfixj.config=file:secrets/quickfixj.cfg \
  -jar target/fix-http-server-*.jar

The server starts on port 9005 by default.

5. Test it

# Health check (no auth required)
curl http://localhost:9005/health

# Request a quote
curl -X POST http://localhost:9005/quote \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{"quoteRequestId":"QR-001","symbol":"EUR/USD","side":"BUY","orderQuantity":100000}'

Configuration

All settings support environment variable overrides. The pattern is:

property.name=${ENV_VAR_NAME:default_value}

Core settings

Property Env var Default Description
server.port SERVER_PORT 9005 HTTP port
spring.datasource.url SPRING_DATASOURCE_URL jdbc:postgresql://localhost:5432/fix_gateway PostgreSQL JDBC URL
spring.datasource.username SPRING_DATASOURCE_USERNAME postgres DB user
spring.datasource.password SPRING_DATASOURCE_PASSWORD Must be set
api.security.keys API_SECURITY_KEYS Must be set. Comma-separated list of valid API keys
quickfixj.config QUICKFIXJ_CONFIG classpath:config/quickfixj.cfg Path to QuickFIX/J config file

FIX-specific settings

Property Env var Default Description
fix.tag15.enabled FIX_TAG15_ENABLED true Include Currency (Tag 15) in QuoteRequest. Set to false for non-production environments where the counterparty does not expect this tag
fix.reset.day FIX_RESET_DAY MONDAY Day of week for weekly sequence number reset
fix.reset.time FIX_RESET_TIME 07:55 Time for weekly reset (HH:mm, 24-hour)
fix.reset.timezone FIX_RESET_TIMEZONE UTC Timezone for the reset schedule

QuickFIX/J session config (quickfixj.cfg)

The gateway expects two FIX sessions with specific names in the session IDs:

  • ST_STREAMING (SenderCompID containing MKT) — market data / quote requests
  • ST_TRADING (SenderCompID containing TRD) — order execution

See secrets.template/quickfixj.cfg.example.txt for a full annotated example.


API Reference

All trading endpoints require X-API-Key: <key> header. The /health endpoint is public.

POST /quote

Request an exchange rate quote without executing a trade.

// Request
{
  "quoteRequestId": "QR-12345",
  "symbol": "EUR/USD",
  "side": "BUY",
  "orderQuantity": 100000,
  "settlementType": "TOD"
}

// Response
{
  "quoteRequestId": "QR-12345",
  "quoteId": "QUOTE-98765",
  "symbol": "EUR/USD",
  "side": "BUY",
  "price": 3.6250,
  "bidPrice": 3.6240,
  "offerPrice": 3.6250,
  "quantity": 100000,
  "settlementType": "TOD",
  "settlementDate": "20251223",
  "validUntil": "2025-12-23T15:02:18Z",
  "timestamp": "2025-12-23T15:01:48Z"
}

POST /order

Execute a trade using a previously obtained quote. Requires quoteRequestId from a prior /quote call.

// Request
{
  "clientOrderId": "ORDER-12345",
  "symbol": "EUR/USD",
  "side": "BUY",
  "orderQuantity": 100000,
  "quoteRequestId": "QR-12345"
}

// Response
{
  "clientOrderId": "ORDER-12345",
  "orderId": "GW-ORD-001",
  "execId": "EXEC-001",
  "orderStatus": "FILLED",
  "executionType": "FILL",
  "symbol": "EUR/USD",
  "side": "BUY",
  "orderQuantity": 100000.0,
  "executedQuantity": 100000.0,
  "executedPrice": 1.1467,
  "settlementType": "TOD",
  "settlementDate": "20260619",
  "timestamp": "2026-06-19T15:02:09Z"
}

POST /quote-order

Request a quote and execute in a single call. Use when you do not need to review the quote before trading.

// Request
{
  "clientOrderId": "ORDER-12345",
  "symbol": "EUR/USD",
  "side": "BUY",
  "orderQuantity": 100000,
  "settlementType": "TOD"
}

Response is the same shape as /order.

Error responses

{
  "code": "INVALID_API_KEY",
  "message": "Invalid API key",
  "timestamp": "2025-12-04T10:30:00.000Z"
}
HTTP status Code Meaning
400 VALIDATION_ERROR Missing or invalid request field
401 MISSING_API_KEY X-API-Key header absent
401 INVALID_API_KEY Key not recognised
408 / 504 REQUEST_TIMEOUT FIX counterparty did not respond in time
500 INTERNAL_ERROR Unexpected server error

Running with Docker

# Build image
docker build -t fix-http-server .

# Or use docker-compose (requires secrets/ directory to be populated first)
docker-compose up

The docker-compose.yml mounts ./secrets/ (gitignored) into the container — populate it with your application.properties and quickfixj.cfg before starting.


Local Development (Mock Simulator)

The bundled quickfixj.cfg (in src/main/resources/config/) connects to a local mock FIX simulator on ports 9877 (market data) and 9878 (trading). You can run any FIX 4.4-compatible acceptor on those ports, for example QuickFIX/J's executor sample.

To skip the FIX connection entirely during development (e.g. for REST layer testing only), you can wire a stub ApplicationAdapter in a test Spring profile.


Architecture

┌─────────────────────────────────────────────────────────┐
│                    Spring WebFlux                        │
│  QuoteController   OrderController   QuoteOrderController│
└──────────────────────────┬──────────────────────────────┘
                           │
┌──────────────────────────▼──────────────────────────────┐
│              Service layer                               │
│  QuoteService    OrderService    QuoteOrderService       │
└──────────────────────────┬──────────────────────────────┘
              ┌────────────┴────────────┐
              ▼                         ▼
┌─────────────────────┐    ┌───────────────────────────┐
│   QuickFIX/J        │    │   PostgreSQL (JPA)        │
│                     │    │                           │
│  ST_STREAMING (MKT) │    │  quote_requests           │
│  ST_TRADING  (TRD)  │    │  orders                   │
└─────────────────────┘    └───────────────────────────┘
         │
         ▼
   FIX Counterparty

Session handling: QuickFixSessionManager manages both FIX sessions. Quote requests are sent via ST_STREAMING; order executions via ST_TRADING. Pending requests are held in an in-memory ConcurrentHashMap with configurable timeouts.

Weekly reset: WeeklyResetScheduler sends a Logon with ResetSeqNumFlag=Y on the configured day/time to re-synchronise sequence numbers with the counterparty.


Contributing

See CONTRIBUTING.md.


Commercial support

For commercial support, enterprise-grade deployments or consulting services, contact us at: 🌐 https://paicore.tech


License

AGPL-3.0-or-later

About

No description, website, or topics provided.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages