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.
The diagram below illustrates the macro-level architecture and data flow between the system's components.
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.
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.
- 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).
- 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).
- 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.
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.
Essential Requirements:
- Java Development Kit (JDK): Version 23 or higher.
- Redis-Compatible Database: The system is compatible with:
- Redis
- Valkey
- Garnet
- KeyDB
- DragonflyDB
- and others.
- Gradle: For building the
analyzer, and samples. - Maven: For building the
benchmarksmodule.
Recommended Additional Tools:
- ELK Stack (Elasticsearch, Logstash, Kibana): Recommended for production-grade, centralized logging.
- Redis Insight: A helpful GUI for inspecting the data store.
- Process Compose, pm2: Useful for managing processes in a bare-metal environment.
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
Brokerabstraction with a default ForexConnect API implementation. - A
Registryabstraction 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.
analyzer uses TOML file format for its configuration.
| Parameter | Description | Example |
|---|---|---|
version |
Configuration version ID | 6b86 |
| Parameter | Description | Example |
|---|---|---|
connection.registry.uri |
URI for the Redis-compatible database. | redis://127.0.0.1:6379 |
| Parameter | Description | Example |
|---|---|---|
connection.broker.login |
Broker authentication login | username |
connection.broker.password |
Broker authentication password | password |
| 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"] |
| 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 |
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.Historycom.jolie.analyzer.broker.Broker.HistoryByStockscom.jolie.analyzer.broker.Broker.HistoryByTimestampscom.jolie.analyzer.broker.Broker.HistoryBatchcom.jolie.analyzer.broker.Broker.Tickcom.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.
This is a standard Gradle project. It respects the GraalVM Native Image readiness guidelines.
-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).
cd analyzer
./gradlew :run --args="-c config.yaml -level DEBUG"Important: If launching manually, remember to set
-Djava.library.pathpointing to the ForexConnect SDK.
The project uses JUnit 5 for unit testing.
cd analyzer
./gradlew :testThe 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.
# 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':: 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\netUsing 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
PATHenvironment variable. Linux users do not need to modifyLD_LIBRARY_PATHdue to the patchedRPATH.
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())
]
}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.jarDue to limited documentation and complex redistribution of the official API resources, the repository includes two minimal, working starting points.
This project demonstrates a minimal, working integration with the ForexConnect SDK using the repackaged libraries
from vendor-forex-connect-sdk.
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.
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 :runThis project is licensed under the MIT License, except for the ForexConnect SDK (see
vendor-forex-connect-sdk/license.txt).
