A service for analyzing cryptocurrency prices and providing investment recommendations based on volatility.
This service allows uploading historical cryptocurrency price data from CSV files, calculating key metrics (min, max, oldest, newest prices), and determining the most volatile assets for a given period or a specific day.
- Java 25: Leveraging the latest language and JVM features.
- Spring Boot 4.0.2: Modern framework for building microservices.
- PostgreSQL 17: Reliable storage for price data.
- Virtual Threads (Project Loom): For high-performance parallel processing of import files.
- ShedLock: Ensures that scheduled import tasks do not overlap in a clustered environment.
- Caffeine Cache: Local caching of heavy query results.
- Bucket4j: Rate Limiting implementation to protect the API from overloads.
- Flyway: Database migrations.
- MapStruct: High-performance mapping between entities and DTOs.
The project is implemented using Hexagonal Architecture (Ports & Adapters).
domain: The core of the system. Contains business logic, domain services (CryptoAnalysisService), and entities. Independent of external frameworks.application: Service layer (CryptoApplicationService), orchestrating business scenarios.infrastructure: Implementation of "adapters" — database interaction, configurations (ShedLock, Caching), error handling.interfaces: System entry points (REST controllers).
- Technology Independence: Business logic doesn't know whether we use PostgreSQL or MongoDB, REST or gRPC.
- Testability: Domain logic is easy to test with unit tests without starting the Spring context.
- Flexibility: Easy to replace implementation details (e.g., import method) without affecting the system core.
- Docker & Docker Compose
- JDK 25
Before starting, ensure your CSV data is located in the ./prices directory.
The application will scan this folder on startup and then once a day according to the configured cron schedule.
- Ensure PostgreSQL is running (you can use
docker-compose up db). - Start the application:
./gradlew bootRun
Build and run the entire environment with a single command:
docker-compose up --buildThe service will be available at: http://localhost:8080
Swagger UI: http://localhost:8080/swagger-ui.html
- Import: Automatic discovery and import of CSV files from a configured directory at startup and on a schedule (once a day).
- Stats: Get full statistics (min, max, oldest, newest) for a specific cryptocurrency.
- Sorting: A list of all currencies sorted by volatility (normalized range).
- Highest Range: Find the most volatile currency for a specific day.
- Rate Limiting: Limit the number of API requests (configurable in
application.yaml).
The service is designed to handle increased load and 100+ new cryptocurrencies:
- Batch Loading: CSV data is loaded in batches (
batch-size: 1000), minimizing database queries. - Virtual Threads: Each import file is processed in a separate virtual thread, allowing efficient CPU usage without overloading the OS with heavy threads.
- Indexes: The
crypto_pricestable has a composite index(symbol, price_timestamp DESC)for instant search and sorting. - Caching: Volatility calculation results are cached via Caffeine, reducing DB load for repeated requests.
- In-Memory Rate Limiting: Local
Bucket4jis used. In a distributed environment (K8s), a transition to a Redis-backed solution may be required. - CSV Validation: Basic format checks are performed. It is assumed that the input data is generally correct.
- No Auth: For demonstration purposes, the API is open without authentication.
- Distributed Locks: ShedLock is configured with a JDBC provider. This ensures that in a multi-instance environment (like Kubernetes), the import task runs only on one instance at a time.
- Batch Ingestion: To ensure performance, the system uses JdbcTemplate for batch inserts, which is significantly faster than standard JPA save calls for large datasets.
To run tests, use:
./gradlew testThe project uses Testcontainers (PostgreSQL) for integration tests, guaranteeing identical behavior in tests and production.
After running the tests, the coverage report is available at:
build/reports/jacoco/test/html/index.html
Minimum coverage threshold is 80%.
- Health Checks: Available at
/actuator/health(Liveness/Readiness for K8s). - Metrics: Prometheus-ready metrics available at
/actuator/prometheus. - Logging: Structured JSON logging is enabled for better integration with ELK/Loki.