Development Documentation
This comprehensive guide covers Planar's architecture, development setup, contribution guidelines, and best practices for extending the framework.
Architecture Overview
System Architecture
Planar follows a modular architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ User Interface Layer │
├─────────────────────────────────────────────────────────────┤
│ Planar.jl (Main) │ PlanarInteractive.jl │ CLI Tools │
├─────────────────────────────────────────────────────────────┤
│ Strategy Layer │
├─────────────────────────────────────────────────────────────┤
│ Strategies.jl │ User Strategies │ StrategyStats│
├─────────────────────────────────────────────────────────────┤
│ Execution Layer │
├─────────────────────────────────────────────────────────────┤
│ SimMode.jl │ PaperMode.jl │ LiveMode.jl │ Executors.jl│
├─────────────────────────────────────────────────────────────┤
│ Data & Exchange Layer │
├─────────────────────────────────────────────────────────────┤
│ Exchanges.jl │ Data.jl │ Fetch.jl │ Processing.jl │ Metrics.jl│
├─────────────────────────────────────────────────────────────┤
│ Foundation Layer │
├─────────────────────────────────────────────────────────────┤
│Engine.jl│Instruments.jl│OrderTypes.jl│Collections.jl│Lang.jl│
└─────────────────────────────────────────────────────────────┘Core Components
Engine Module
The foundation of Planar, providing:
- Asset Management:
AbstractAsset,Asset,Derivativetypes - Instance System:
AssetInstancelinking assets to exchanges - Strategy Framework:
Strategy{Mode}parametric types - Core Abstractions: Base types and interfaces
Execution Modes
Three distinct execution environments:
- SimMode: Fast synchronous backtesting-mode) with OHLCV data
- PaperMode: Real-time simulation with live data feeds
- LiveMode: Actual trading with exchanges APIs
Data Pipeline
Comprehensive data management:
- Fetch: Data acquisition from exchanges and external sources
- Processing: Data cleaning, resampling, and transformation
- Storage: Zarr-based large dataset storage with LMDB indexing
- Watchers: Real-time data monitoring and alerting
Exchange Integration
Unified exchange interface:
- CCXT Integration: 100+ exchange support via Ccxt.jl
- Custom Exchanges: Framework for implementing proprietary APIs
- Order Management: Unified order types across exchanges
Module Relationships
graph TD
A[Planar.jl] --> B[Engine.jl]
A --> C[Strategies.jl]
A --> D[SimMode.jl]
A --> E[PaperMode.jl]
A --> F[LiveMode.jl]
C --> B
D --> B
E --> B
F --> B
B --> G[Instruments.jl]
B --> H[OrderTypes.jl]
B --> I[Executors.jl]
D --> J[Data.jl]
E --> J
F --> J
J --> K[Fetch.jl]
J --> L[Processing.jl]
F --> M[Exchanges.jl]
E --> M
M --> N[ExchangeTypes.jl]
O[PlanarInteractive.jl] --> A
O --> P[Plotting.jl]
O --> Q[Optim.jl]Data Flow Architecture
sequenceDiagram
participant U as User Strategy
participant S as Strategy Engine
participant E as Execution Mode
participant D as Data Layer
participant X as Exchange
U->>S: Initialize Strategy
S->>D: Load Historical Data
D->>S: Return [OHLCV](guides/../guides/data-management.md#ohlcv-data) Data
loop Trading Loop
S->>U: Call Strategy Logic
U->>S: Generate Signals
S->>E: Execute Orders
E->>X: Place Orders (Live/Paper)
X->>E: Order Confirmation
E->>S: Update Positions
S->>D: Log Trade Data
endDevelopment Setup
Prerequisites
- Julia 1.11+: Latest stable Julia version
- Git: With submodule support
- Python 3.8+: For CCXT integration (managed via CondaPkg)
- Docker (optional): For containerized development
Initial Setup
- Clone Repository:
git clone --recurse-submodules https://github.com/defnlnotme/Planar.jl
cd Planar.jl- Environment Setup:
# Enable direnv (recommended)
direnv allow
# Or manually set environment
export JULIA_PROJECT=Planar
export JULIA_NUM_THREADS=$(nproc)- Install Dependencies:
Development Environment
Recommended Julia Setup
IDE Configuration
VS Code with Julia Extension:
{
"julia.environmentPath": "Planar",
"julia.enableTelemetry": false,
"julia.execution.resultDisplay": "both",
"julia.lint.run": true,
"julia.format.indent": 4,
"julia.format.margin": 92
}Vim/Neovim with LanguageServer.jl:
require'lspconfig'.julials.setup{
settings = {
julia = {
environmentPath = "Planar",
format = {
indent = 4,
margin = 92
}
}
}
}PlanarDev Utilities
The PlanarDev package assists developers by providing helper functions for working with Planar and for conducting tests.
Precompilation Control
To skip precompilation for selected modules, set the JULIA_NOPRECOMP environment variable:
Alternatively, you can manage environment variables with direnv (refer to the .envrc in the repository). To disable precompilation entirely for certain packages, use JULIA_NOPRECOMP=all. This is recommended only when altering low-level components of the module stack. Remember to clear the compilation cache when changing precompilation settings:
The Exchanges and Fetch packages contain a compile.jl file to generate precompile statements using CompileBot.jl. This is particularly useful for precompilation tasks that involve numerous web requests. However, this method is not currently used as it does not compile as many methods as PrecompileTools.
For custom method precompilation, enclose your code with py_start_loop and py_stop_loop from the Python package to prevent Pkg from stalling due to lingering threads.
Method Invalidation Strategy
The order of using ... statements when loading modules can influence method invalidation. To minimize invalidation, arrange the module imports starting with the ones most likely to cause invalidations to the ones least likely. For instance, placing using Python at the beginning can expedite loading times:
Modules known for heavy invalidations:
- Python
- Ccxt (initiates the Python async loop)
- Data (relies on Zarr and DataFrames)
- Plots (depends on Makie)
To reduce invalidations, include external modules in only one local package and then use that package as a dependency in other local packages. For instance, if DataFrames is a dependency of the local package Data, and you want to use DataFrames in the Stats package, do not add DataFrames to Stats dependencies. Instead, use Data and import DataFrames from there:
Handling Segfaults
In rare cases involving complex multi-threaded scenarios, disable and re-enable the garbage collector (GC) around the loading of Planar to avoid segmentation faults:
Refer to PythonCall.jl issue #201 for more details.
Dependency Management
When adding dependencies, ensure that a dependency is only included in one subpackage. If you need the same dependency in another subpackage, add the first subpackage as the dependency, not the external module.
The order of using or import statements within packages is crucial. Always import external dependencies before internal ones to minimize method invalidations.
See Also
- Exchanges - Exchange integration and configuration
- Config - Exchange integration and configuration
- Overview - Troubleshooting: Troubleshooting and problem resolution
- Optimization - Performance optimization techniques
- Performance Issues - Troubleshooting: Performance optimization techniques
- Data Management - Guide: Data handling and management
Contribution Guidelines
Code Style and Standards
Julia Formatting
Planar uses JuliaFormatter with Blue style:
Configuration in .JuliaFormatter.toml:
style = "blue"
margin = 92
indent = 4
always_for_in = true
whitespace_typedefs = true
whitespace_ops_in_indices = true
remove_extra_newlines = trueNaming Conventions
- Types: PascalCase (
MyCustomType) - Functions: snakecase (`myfunction`)
- Constants: UPPERCASE (`MYCONSTANT`)
- Modules: PascalCase (
MyModule) - Variables: snakecase (`myvariable`)
Documentation Standards
All public functions must have docstrings:
Testing Patterns
Unit Testing Structure
Integration Testing
Property-Based Testing
Extension Best Practices
Creating New Modules
- Module Structure:
MyNewModule/
├── Project.toml
├── Manifest.toml
├── src/
│ ├── MyNewModule.jl
│ ├── types.jl
│ ├── functions.jl
│ └── utils.jl
├── test/
│ ├── runtests.jl
│ └── test_functions.jl
└── README.md- Project.toml Template:
name = "MyNewModule"
uuid = "generate-new-uuid"
authors = ["Your Name <your.email@example.com>"]
version = "0.1.0"
[deps]
# Only essential dependencies
Engine = {path = "../Engine"}
[compat]
julia = "1.11"- Module Definition:
Implementing Custom Strategies
Performance Optimization Guidelines
Type Stability:
Memory Allocation:
Benchmarking:
Debugging and Profiling
Debugging Strategies
Logging:
Interactive Debugging:
Testing Utilities:
Performance Profiling
Continuous Integration
GitHub Actions Workflow
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
julia-version: ['1.11', '1.12']
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.julia-version }}
- uses: julia-actions/cache@v1
- uses: julia-actions/julia-buildpkg@v1
with:
project: Planar
- uses: julia-actions/julia-runtest@v1
with:
project: Planar
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v3Release Process
Version Management
Semantic Versioning: Follow SemVer (MAJOR.MINOR.PATCH)
- MAJOR: Breaking changes
- MINOR: New features, backward compatible
- PATCH: Bug fixes, backward compatible
Release Checklist:
- [ ] Update version in Project.toml
- [ ] Update CHANGELOG.md
- [ ] Run full test suite
- [ ] Update documentation
- [ ] Create release tag
- [ ] Build and test Docker images
Documentation Updates
Community Guidelines
Issue Reporting
When reporting issues, include:
- Julia version and Planar version
- Minimal reproducible example
- Expected vs actual behavior
- Error messages and stack traces
- System information (OS, architecture)
Pull Request Process
- Fork the repository
- Create feature branch from
develop - Make changes with tests
- Update documentation
- Submit pull request with clear description
- Address review feedback
- Merge after approval
Code Review Standards
- Functionality: Does the code work as intended?
- Performance: Are there performance implications?
- Style: Does it follow project conventions?
- Tests: Are there adequate tests?
- Documentation: Is it properly documented?
- Breaking Changes: Are breaking changes justified and documented?
This comprehensive development guide ensures consistent, high-quality contributions to the Planar ecosystem.