Contributing to ExPostFacto
View SourceThank you for your interest in contributing to ExPostFacto! This document provides guidelines and information for contributing to this Elixir backtesting library.
๐ Getting Started
Prerequisites
- Elixir 1.12 or later
- Erlang/OTP 24 or later
- Git
Setting Up Your Development Environment
Fork and clone the repository:
git clone https://github.com/your-username/ex_post_facto.git cd ex_post_factoInstall dependencies:
mix deps.getRun the test suite to ensure everything works:
mix testCheck code formatting:
mix format --check-formatted
๐ Development Guidelines
Code Formatting and Standards
Always run mix format after making any code changes. This ensures consistent formatting across the codebase using the standard Elixir formatter configuration defined in .formatter.exs.
Follow these Elixir best practices:
- Documentation: Include proper
@moduledocand@docattributes for all public modules and functions - Type Specifications: Use
@spectype annotations for all public functions - Naming Conventions: Follow Elixir conventions (snake_case for functions/variables, PascalCase for modules)
- Pattern Matching: Prefer pattern matching over conditional statements when possible
- Error Handling: Use
{:ok, result}and{:error, reason}tuples consistently - Function Design: Keep functions small and focused on a single responsibility
- Data Flow: Use
|>pipe operator for data transformations - Complex Operations: Use
withstatements for complex nested operations - Exception Functions: Use
!suffix for functions that raise exceptions (e.g.,backtest!)
Code Quality Requirements
- No Compiler Warnings: Fix all compiler warnings when possible
- Test Coverage: Add comprehensive tests for new functionality
- Documentation: Include examples in documentation
- Type Safety: Add type specs for all public functions
- Performance: Consider performance implications for large datasets
- Backward Compatibility: Maintain backward compatibility when modifying public APIs
๐๏ธ Project Architecture
ExPostFacto is a backtesting library for trading strategies with the following core architecture:
Core Modules
ExPostFacto: Main entry point withbacktest/3andbacktest!/3functionsExPostFacto.Result: Manages backtesting results and statistics compilationExPostFacto.DataPoint: Represents individual price data points with actionsExPostFacto.InputData: Handles data munging and preprocessingExPostFacto.Output: Contains the final output structure
Trading Strategy Framework
- Supports pluggable strategies through module-function-arguments tuples
{Module, :function, args} - Example strategies in
ExPostFacto.ExampleStrategies - Strategy behaviour pattern for advanced state management
Trade Statistics Engine
The ExPostFacto.TradeStats namespace contains performance metrics calculations:
CompilePairs: Groups buy/sell actions into trade pairsDrawDown: Calculates drawdown metricsTotalProfitAndLoss: Computes P&LWinRate: Computes win statistics- And more...
๐งช Testing Guidelines
Running Tests
# Run all tests
mix test
# Run specific test file
mix test test/ex_post_facto_test.exs
# Run tests with coverage
mix test --cover
Test Organization
Tests are organized to mirror the lib structure:
- Unit tests for individual modules
- Integration tests for end-to-end scenarios
- Test helpers for generating mock data (
CandleDataHelper)
Writing Good Tests
- Descriptive test names that explain what is being tested
- Arrange-Act-Assert pattern for test structure
- Mock data helpers for consistent test data
- Edge case testing (empty data, nil values, boundary conditions)
- Property-based testing where appropriate
- Integration tests with real market data when possible
๐ง Types of Contributions
๐ Bug Reports
When reporting bugs, please include:
- Elixir and Erlang versions
- Minimal reproduction example
- Expected vs actual behavior
- Stack trace (if applicable)
- Data samples that cause the issue (anonymized if needed)
โจ Feature Requests
For new features, please:
- Check existing issues to avoid duplicates
- Describe the use case and problem being solved
- Propose the API or interface design
- Consider backward compatibility
- Discuss performance implications
๐ Documentation Improvements
Documentation contributions are highly valued:
- API documentation improvements
- Tutorial and guide enhancements
- Example strategies and use cases
- Performance tips and best practices
- Migration guides for breaking changes
๐ Code Contributions
Strategy Examples
New example strategies should:
- Demonstrate specific trading concepts
- Include comprehensive documentation
- Have corresponding tests
- Follow the established patterns
Example structure:
defmodule ExPostFacto.ExampleStrategies.MyStrategy do
@moduledoc """
A strategy that demonstrates [specific concept].
## Example
{:ok, result} = ExPostFacto.backtest(
data,
{ExPostFacto.ExampleStrategies.MyStrategy, [param: value]}
)
"""
@doc """
Strategy implementation with proper documentation.
"""
@spec call(map(), ExPostFacto.Result.t(), keyword()) :: ExPostFacto.action()
def call(data, result, opts \\ []) do
# Implementation
end
endTechnical Indicators
New indicators should:
- Follow the existing indicator API patterns
- Include mathematical documentation
- Have comprehensive test coverage
- Handle edge cases (insufficient data, etc.)
Performance Improvements
- Profile before optimizing to identify actual bottlenecks
- Benchmark changes to measure improvement
- Consider memory usage alongside execution time
- Maintain accuracy while improving performance
๐ Development Workflow
1. Create a Feature Branch
git checkout -b feature/my-new-feature
# or
git checkout -b fix/bug-description
2. Make Your Changes
- Write code following the guidelines above
- Add or update tests
- Update documentation
- Run
mix formatto format code - Ensure tests pass with
mix test
3. Commit Your Changes
Use descriptive commit messages:
git add .
git commit -m "Add RSI divergence detection strategy
- Implement bullish and bearish divergence detection
- Add comprehensive tests with edge cases
- Include usage examples in documentation"
4. Push and Create Pull Request
git push origin feature/my-new-feature
Then create a pull request with:
- Clear description of changes
- Link to related issues
- Testing instructions
- Breaking changes (if any)
๐ Pull Request Checklist
Before submitting a pull request, ensure:
- [ ] Tests pass:
mix testruns without failures - [ ] Code formatted:
mix formathas been run - [ ] No warnings: Code compiles without warnings
- [ ] Documentation updated: For new features or API changes
- [ ] Tests added: For new functionality
- [ ] Backward compatibility: Maintained for public APIs
- [ ] Performance considered: For changes affecting large datasets
- [ ] Examples provided: For new strategies or features
๐ฏ Areas Needing Contribution
Based on TODOs and planned enhancements:
- Concurrent Statistics: Make trade statistics calculations concurrent
- Additional Metrics: More comprehensive backtesting metrics
- Strategy Framework: Expand strategy capabilities
- Performance Optimization: Memory and speed improvements
- Data Sources: Additional data input formats
- Visualization: Enhanced charting and reporting
- Risk Management: Position sizing and risk controls
๐ค Community Guidelines
- Be respectful and inclusive in all interactions
- Help others learn and contribute
- Ask questions when you need clarification
- Share knowledge through documentation and examples
- Follow the code of conduct (be kind and professional)
๐ Getting Help
- GitHub Issues: For bugs and feature requests
- Discussions: For questions and general discussion
- Documentation: Check existing docs first
- Code Examples: Look at existing strategies and tests
๐ท๏ธ Release Process
For maintainers:
- Update CHANGELOG.md with new features and fixes
- Bump version in
mix.exs - Run full test suite including integration tests
- Update documentation if needed
- Create git tag and push
- Publish to Hex with
mix hex.publish
Thank you for contributing to ExPostFacto! Your contributions help make algorithmic trading more accessible to the Elixir community. ๐
โก Quick Reference
# Essential commands
mix deps.get # Install dependencies
mix test # Run tests
mix format # Format code
mix docs # Generate documentation
Remember: Always run mix format before committing!