feat: Implement v0.2 backtesting engine and CLI#7
Merged
impatient0 merged 69 commits intodevelopfrom Nov 7, 2025
Merged
Conversation
- Define a new module in the root POM - Create module's own POM with basic dependencies
- Logically group dependencies in POMs and add comments to each group
- Create `Candle`, `Position` and `Trade` domain models - Create a `TradeDirection` domain enum
- Create `Strategy` interface defining the contract for the analytical component - Create `TradingContext` interface defining the contract for the environment `Strategy` operates within
- Define a new module in the root POM - Create module's own POM with basic dependencies
- Add method declarations to TradingContext interface - Create data model for backtester consisting of BacktestConfig and BacktestResult
- Create initial (stubbed) implementation for BacktestEngine
- Make TradingContext interface more flexible by introducing a submitOrder(...) method that allows opening, scaling and closing positions
- Update BacktestEngine to implement the evolved TradingContext - Refine position handling logic
- Update BacktestConfig to include trading fees and slippage parameters
- Implement logic for calculating the costs of opening and closing positions, as well as liquidation cost for the final position - Correct the cash flow logic for opening/closing SHORT positions
- Create descriptive Javadocs for all fields and methods in BacktestEngine that previously weren't annotated
- Create a0-backtester/README.md with a detailed description of module's functionality - Update README.md and ARCHITECTURE.md to reflect the changes to project's current state and roadmap
- replace `get(....size() - 1)` with `getLast()`
- Replace the stubbing `Object` with an actual `Strategy` field in BacktestConfig - Use the `Strategy` object in the engine's main loop
- Create ConfigurableTestStrategy that executes a predefined set of actions - Create TestDataFactory that produces test candle data
- Implement a test verifying that P/L is calculated correctly if a strategy opens one LONG position and never closes it
- Log message for opening a position now indicates the volume of the asset
- Add test verifying that orders with a cost exceeding available balance are ignored - Add test verifying that orders for a new symbol are ignored if another position is already open - Add test verifying that scale-out order exceeding position size closes the position - Add test verifying that closing a position and opening a new one on a different symbol is handled correctly
- Update backtester's own README.md to reflect the implemented functionality - Tick off the corresponding item in the project-level README.md roadmap list
- Add a note to the BacktestConfig Javadoc indicating that it requires a fresh instance of a `Strategy` object - Add a similar note to backtester's README.md
- Update project-level README.md and ARCHITECTURE.md to reflect the revised implementation plan, introducing a new `a0-strategy-rules-engine` module
- Update strategy example in ARCHITECTURE.md to reflect the new architecture
- Implement logic that calculates and locks the collateral for SHORT trades. All LONG trades are considered spot trades, and SHORT trades are considered margin trades for the purpose of simplicity
- Create an AccountMode enum - Add a corresponding field to BacktestConfig
- Make the engine aware of account mode and have business logic branch accordingly
- Define collateral ratios in a dedicated YAML file - Create a CollateralRatioLoader config class
- Update BacktestConfig to store multiple streams of candle data - Rename `collateral` to `costBasis` in Position for clarity in context of spot positions - Adapt TradingContext for positions in multiple symbols
- Remove the `updateCurrentPrices` as it should be package-private - Update Javadocs to be more clear
- Update group ID for Jackson dependencies from legacy `com.fasterxml.jackson...` to `tools.jackson...`
- Implement data transfer objects for strategy configuration
- Refactor StrategyConfig into a record class and include a new `timeframe` field
- Create an Indicator interface defining the contract for an indicator - Implement an RsiIndicator using the TA4j library
- Introduce a new MarketEvent record class carrying candle and symbol information - Strategy now has a `void onMarketEvent(...)` method instead of the `void onCandle(...)`
- Refactor the main loop to feed MarketEvents into strategies
- Refactor tests to correctly use MarketEvent
- Refactor TradingContext by introducing more methods to provide detailed read-only view of the trading account state
- Implement the new methods from TradingContext in the BacktestTradingContext - Replace the `getWalletBalanceForTest` method usage with `getAssetBalance`
- Expand config to include position sizing - Implement exit and sizing logic - Implement the strategy class
- Create TimeframeParser utility class - Implement StrategyLoader able to load strategies from YAML configs
- Implement the TimeframeParserTest class - Add a `junit-jupiter-params` dependency
- Add Lombok `@With` annotation to generate corresponding methods in Candle class
- Create TakeProfitRuleTest and StopLossRuleTest verifying that the rules trigger correctly
- Create RsiIndicatorTest verifying that signals are being triggered correctly
- Add package-private getters to RulesBasedStrategy to enable integration testing of StrategyLoader
- Verify happy path of successfully loading a strategy - Verify graceful failure when loading from incorrect or malformed config
…rategy - Using mocked strategy components (indicators, sizers, exit rules), verify that the strategy operates them correctly
- Create module-level README.md providing detailed description of `a0-strategy-rules-engine` functionality - Update project-level documentation, detailing architecture changes and roadmap progress
- Create new module, initialize necessary dependencies and configure build
- Implement a BacktesterCli class with a stubbed `call()` method for now
- Implement CsvDataLoader class that reads data from a CSV file and converts it to a `List<Candle>`
- Fully implement the `call()` method inside the BacktesterCli class
- Wrap the `call()` method body in `try-catch` and print more user friendly error messages
- Verify various scenarios, including a "happy path", malformed data, incorrect command-line arguments, etc.
- Configure build to eliminate some artifact clash shade warnings (some are still present though)
- Create module-level README.md providing detailed description of `a0-backtester-cli` functionality - Update project-level documentation, detailing architecture changes and roadmap progress
- Remove unused imports - Replace statement lambdas with expressions for conciseness
4314159 to
ca3b261
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This pull request marks the completion of the v0.2 project epic, delivering a complete, end-to-end backtesting system for the A-Zero framework. It integrates three new major modules (
a0-backtester,a0-strategy-rules-engine,a0-backtester-cli) and refactors thea0-coreto create a cohesive, user-facing application.With this change, a user can now define a complex trading strategy in a declarative YAML file, run it against historical data, and receive a detailed performance summary, all from the command line. This PR transforms the project from a set of foundational libraries into a fully functional, data-driven tool for systematic strategy evaluation.
Key Features
Standalone CLI Application (
a0-backtester-cli): A new, executable uber-jar that serves as the primary user interface. It is built withpicoclifor robust argument parsing, provides clear user feedback, and prints a formatted summary of backtest results.Declarative Rules Engine (
a0-strategy-rules-engine): A powerful new library that parses strategy logic from YAML files.Sophisticated Portfolio Margin Engine (
a0-backtester): A major refactoring of the backtesting engine to simulate a professional-grade portfolio margin system (inspired by the Bybit UTA).walletto track both owned assets and borrowed liabilities.collateral-ratios.yaml.Architectural Enhancements (
a0-core): The core interfaces have been evolved to support a multi-asset, event-driven architecture.MarketEventrecord for clean, extensible data passing.TradingContextinterface to provide strategies with a rich, read-only view of account NAV, margin equity, and wallet balances.Comprehensive Test Suite: A full suite of JUnit 5 and Mockito tests has been developed for all new modules. The suite includes:
RulesBasedStrategy's decision-making logic.BacktestEngine, validating critical edge cases like margin calls, liquidations, and complex accounting scenarios.This pull request completes all planned work for v0.2. It delivers the core value proposition of the A-Zero project and establishes a robust, tested foundation for future work on paper trading and live execution.