Skip to content

A strategy trading testing framework targeting ForexConnect SDK written in Java.

License

Notifications You must be signed in to change notification settings

nadvotsky/jolie

Repository files navigation

jolie

Java 23 Redis Gradle Maven License

Overview

jolie is an experimental trading strategy testing suite designed to balance:

  • Performance and developer productivity
  • Feature richness with easy deployment
  • Architecture clarity
  • Modern yet pragmatic solutions

At its core, jolie processes live market data, analyzes historical candle patterns, and generates actionable short/long trade predictions based on configurable breakout conditions.

System Architecture

The diagram below illustrates the macro-level architecture and data flow between the system's components.

Solution Diagram

Architecture Philosophy

The implementation of jolie aims to find an effective trade-off between competing development concerns, and follows a pragmatic approach:

  • It uses the robust, high-performance Java ecosystem. This choice provides a strong foundation for computationally intensive tasks while maintaining excellent developer productivity and tooling support.
  • It utilizes a cross-platform subset of Redis key-value store for session management, signal propagation, and caching. This ensures broad compatibility with in-memory databases like Valkey, Garnett, KeyDB, and DragonflyDB.
  • The project intentionally avoids two extremes. It is not a complex, hard-to-manage microservice mesh requiring service discovery, gateways, and container orchestration. It is also not a rigid monolith. Instead, its core components are distinct processes communicating via a Pub/Sub channel, making them easy to develop, test, and deploy independently while maintaining a clear and manageable system architecture.
  • The project embraces modern development practices with a focus on simplicity and efficiency. The entire codebase is designed with KISS (Keep It Simple, Stupid) principles in mind and is structured to be compatible with GraalVM Native Image, allowing for the creation of lean, self-contained native executables.

Signal Activation

The algorithm behind signal activation analyzes the last N historical candles and one of the final ticks of the current, pending candle. It performs specific tests on the close price and the difference between the candle's close and open values to predict a short or long position.

  1. Reference Window Analysis: From the last N fully closed candles, the algorithm determines:
    • The highest closing price.
    • The lowest closing price.
    • The largest single-candle change (close - open).
    • The smallest single-candle change (close - open).
  2. Pre-Close Evaluation:
    • The algorithm reconstructs a partial candle from the latest tick data just before the current candle fully forms. (e.g., ~10 seconds before the end of a 5-minute candle, but both values are configurable).
  3. Breakout Detection:
    • If the reconstructed candle’s close AND price change exceed corresponding historical maxima, a short signal is triggered.
    • If they fall below historical minima, a long signal is triggered.

This method enables the system to predict movements just before the candle closes, maximizing the reaction window for order placement.

Project Hierarchy

The solution is composed of the following subprojects:

  • analyzer: The core microservice responsible for strategy analysis and signal generation.
  • vendor-forex-connect-sdk: A repackaged version of the FXCM ForexConnect SDK.
  • benchmarks: A JMH suite for performance testing of critical code paths.
  • sandbox-forex-connect-api: A minimal working example for the ForexConnect SDK.
  • sandbox-java-api: A minimal working example for the FXCM Java API.
  • share: Documentation, scripts, and supporting assets.

Prerequisites

Essential Requirements:

Recommended Additional Tools:

analyzer

The analyzer is the brain of the operation. This microservice subscribes to market data streams, applies the core trading logic, and generates signals.

It currently implements the following:

  • A command-line interface (CLI).
  • Configurable logging (plain text or JSON for ELK integration).
  • Dynamic configuration parsing with automatic hot-reloading on changes.
  • A pluggable Broker abstraction with a default ForexConnect API implementation.
  • A Registry abstraction to interact with the Redis-compatible data store for caching and data exchange.
  • The main algorithm implementation, with automatic dispatch to vectorized operations where available.

Configuration

analyzer uses TOML file format for its configuration.

Core

Parameter Description Example
version Configuration version ID 6b86

Registry

Parameter Description Example
connection.registry.uri URI for the Redis-compatible database. redis://127.0.0.1:6379

Broker

Parameter Description Example
connection.broker.login Broker authentication login username
connection.broker.password Broker authentication password password

Algorithm

Parameter Description Example
algorithm.subtract Offset before candle close to run evaluation 00:00:10
algorithm.stocks List of currency pairs to analyze. ["EUR/USD", "GBP/USD"]
algorithm.timings List of time periods to analyze, filtering out periods of no interest. ["10:55:00"]

History

Parameter Description Example
algorithm.history.duration Duration of a single historical candle. 00:05:00
algorithm.history.total Number of candles in analysis window 12

Pluggable Broker Architecture

The Broker abstraction provides a flexible mechanism for fetching market data. This allows to separate the core logic from any specific data provider and unlocks the intelligent performance optimizations, such as auto-vectorization.

While the official ForexConnect SDK is the default implementation, the architecture makes it straightforward to migrate to or integrate other popular data providers:

The core of this abstraction is a set of interfaces that components can implement to specify the most efficient available operations:

  • com.jolie.analyzer.broker.Broker.History
  • com.jolie.analyzer.broker.Broker.HistoryByStocks
  • com.jolie.analyzer.broker.Broker.HistoryByTimestamps
  • com.jolie.analyzer.broker.Broker.HistoryBatch
  • com.jolie.analyzer.broker.Broker.Tick
  • com.jolie.analyzer.broker.Broker.TicksByStocks

This design allows the analyzer to intelligently parallelize requests. For instance, if a Broker implementation supports batched (HistoryBatch) or vectorized history fetching (HistoryByStocks), the system can process multiple stocks concurrently in a thread pool, improving data fetching speed, while prioritizing those currencies that yield the best win/lose ratio.

Execution

This is a standard Gradle project. It respects the GraalVM Native Image readiness guidelines.

CLI Parameters

  • -c <CONFIG>, -[-]config[=]<CONFIG>: Path to the configuration file.
  • -l <LEVEL>, -[-]level[=]<LEVEL>: Sets the logging level. Must be one of: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL.
  • -p, -[-]prod: Production mode (enables JSON logging and security restrictions).

Example

cd analyzer
./gradlew :run --args="-c config.yaml -level DEBUG"

Important: If launching manually, remember to set -Djava.library.path pointing to the ForexConnect SDK.

Testing

The project uses JUnit 5 for unit testing.

cd analyzer
./gradlew :test

vendor-forex-connect-sdk

The original Forex Connect SDK can be challenging to configure and get started, so this directory directory contains pre-packaged libraries to provide a quick start for developers.

Building

Linux

# Download the latest SDK from https://fxcodebase.com/wiki/index.php/Download

# Create the output directory
mkdir -p vendor-forex-connect-sdk/linux-amd64
cd vendor-forex-connect-sdk/linux-amd64

# Unpack the essential SDK directories
tar \
    --extract --verbose --file ~/Downloads/ForexConnectAPI-1.6.5-Linux-x86_64.tar.gz \
    --strip-components 2 --exclude samples --exclude doc --exclude include --exclude net

# Consolidate Java libraries
mv java/* ./
rmdir java

# Fix shared object permissions
chmod 755 *.so

# Patch RPATH to point to $ORIGIN, making libraries self-contained
find -type f -not -path '*.jar' | xargs patchelf --set-rpath '$ORIGIN'

Windows

:: Download the latest SDK from https://fxcodebase.com/wiki/index.php/Download

:: Create the output directory
mkdir vendor-forex-connect-sdk\windows-amd64
cd vendor-forex-connect-sdk\windows-amd64

:: Unpack the required libraries
7z e %USERPROFILE%\Downloads\ForexConnectAPI-1.6.5-win64.exe -i!bin -x!bin\net

Using

Using the ForexConnect SDK requires including the JAR files at compile time and specifying java.library.path JVM argument at runtime.

NOTE: Windows users must also add the SDK directory to their PATH environment variable. Linux users do not need to modify LD_LIBRARY_PATH due to the patched RPATH.

Example Gradle configuration with the application plugin:

// build.gradle

// Define a path that resolves to the correct OS/architecture-specific SDK directory
def fxcmSDK = '../vendor-forex-connect-sdk/%s-%s'.formatted(
    System.getProperty('os.name').split().first().toLowerCase(),
    System.getProperty('os.arch')
)

// Include the SDK's JAR files as dependencies
dependencies {
    // ...
    implementation fileTree(fxcmSDK.toString()) {
        include '*.jar'
    }
}

// Add the JVM argument to the application's run configuration
application {
    // ...
    applicationDefaultJvmArgs = [
        '-Djava.library.path=%s'.formatted(fxcmSDK.toString())
    ]
}

benchmarks

This subproject provides a suite of JMH (Java Microbenchmark Harness) benchmarks to evaluate the performance characteristics of core algorithms.

The primary goal is to observe how different implementation strategies impact the computational core of the analyzer, specifically the logic for fetching data from the cache, detecting gaps, and filling them with results from the broker.

It measures various optimization techniques, such as caching intermediate min/max results, using imperative loops instead of the Stream API, and more. See the source code for details.

As always, note that results are machine- and JVM-specific. Aggressive JIT compilers in modern JVMs like GraalVM may produce different outcomes. However, tests have consistently shown that for these performance-critical code paths, traditional loops often outperform functional equivalents.

cd benchmarks
./mvnw clean verify
java -jar target/benchmarks.jar

Sandbox Projects

Due to limited documentation and complex redistribution of the official API resources, the repository includes two minimal, working starting points.

sandbox-forex-connect-api

This project demonstrates a minimal, working integration with the ForexConnect SDK using the repackaged libraries from vendor-forex-connect-sdk.

sandbox-java-api

This project is a demo of the official FXCM Java API. It is worth noting that FXCM Java API is less supported than the ForexConnect SDK.

Running

Both sandbox projects are standard Gradle projects targeting Java 23+.

cd sandbox-forex-connect-api
# Edit the credentials in source code first
./gradlew :run

cd sandbox-java-api
# Edit the credentials in source code first
./gradlew :run

License

This project is licensed under the MIT License, except for the ForexConnect SDK (see vendor-forex-connect-sdk/license.txt).

About

A strategy trading testing framework targeting ForexConnect SDK written in Java.

Topics

Resources

License

Stars

Watchers

Forks