Strategy Development Guide
This comprehensive guide covers everything you need to know about developing trading strategies in Planar. From basic concepts to advanced patterns, you'll learn how to build robust, profitable trading systems using Julia's powerful dispatch system.
Quick Navigation
- Strategy Fundamentals - Core concepts and architecture
- strategies - Interactive and manual setup
- Strategy Interface - Understanding the call! dispatch system
- Advanced Examples - Multi-timeframe, portfolio, and optimization strategies
- Best Practices - Code organization and performance tips
- troubleshooting - Common issues and solutions
Prerequisites
Before diving into strategy development, ensure you have:
- Completed the Getting Started Guide
- Basic understanding of Data Management
- Familiarity with Execution Modes
Related Topics
- optimization - Parameter tuning and backtesting-mode)
- Plotting - Visualizing strategy performance
- Customization - Extending strategy functionality
Strategy Fundamentals
Architecture Overview
Planar strategies are built around Julia's powerful dispatch system, enabling clean separation of concerns and easy customization. Each strategy is a Julia module that implements specific interface methods through the call! function dispatch pattern.
Core Components
- Strategy Module: Contains your trading logic and configuration
- Dispatch System: Uses
call!methods to handle different strategy events - Asset Universe: Collection of tradeable assets managed by the strategy
- Execution Modes: Sim (backtesting-mode)), Paper (simulated live), and Live trading
- Margin Support: Full support for isolated and cross margin trading
Strategy Type Hierarchy
Where:
Mode: Execution mode (Sim, Paper, Live)Name: Strategy module name as SymbolExchange: Exchange identifierMargin: Margin mode (NoMargin, Isolated, Cross)QuoteCurrency: Base currency symbol
Dispatch System
The strategy interface uses Julia's multiple dispatch through the call! function. This pattern allows you to define different behaviors for different contexts while maintaining clean, extensible code.
Key Dispatch Patterns
Type vs Instance Dispatch:
- Methods dispatching on
Type{<:Strategy}are called before strategy construction - Methods dispatching on strategy instances are called during runtime
Action-Based Dispatch:
Exchange-Specific Dispatch
You can customize behavior for specific exchanges:
Margin Trading Concepts
Planar provides comprehensive margin trading support with proper position management and risk controls.
Margin Modes
NoMargin: Spot trading only
Isolated Margin: Each position has independent margin
Cross Margin: Shared margin across all positions
Position Management
Risk Management Patterns
Creating Strategies
Interactive Strategy Generator
The simplest way to create a strategy is using the interactive generator, which prompts for all required configuration options:
Non-Interactive Strategy Creation
You can also create strategies programmatically without user interaction:
Manual Strategy Setup
If you want to create a strategy manually you can either:
- Copy the
user/strategies/Template.jlto a new file in the same directory and customize it - Generate a new project in
user/strategiesand customizeTemplate.jlto be your project entry file
For more advanced setups you can also use Planar as a library, and construct the strategy object directly from your own module:
Project-Based Strategies
For complex strategies, use the project structure:
user/strategies/MyStrategy/
├── Project.toml # Package definition and dependencies
├── Manifest.toml # Locked dependency versions
├── src/
│ ├── MyStrategy.jl # Main strategy module
│ ├── indicators.jl # Custom indicators
│ ├── utils.jl # Utility functions
│ └── risk.jl # Risk management
└── test/
└── test_strategy.jl # Strategy testsStrategy Interface
Loading a Strategy
Strategies are instantiated by loading a Julia module at runtime:
The strategy name corresponds to the module name, which is imported from:
user/strategies/Example.jl(single file strategy)user/strategies/Example/src/Example.jl(project-based strategy)
Strategy Type Structure
Basic Strategy Module
Function Signature Convention
The call! function follows a consistent signature pattern:
- Subject: Either strategy type (
Type{<:Strategy}) or instance (Strategy) - Arguments: Function-specific parameters
- Verb: Action type that determines the dispatch (e.g.,
::LoadStrategy) - Keyword Arguments: Optional parameters
Strategy Lifecycle
Understanding the strategy lifecycle is crucial for proper implementation:
- Module Loading: Strategy module is imported
- Type Construction: Strategy type is created with parameters
- Instance Creation:
call!(Type{<:SC}, config, ::LoadStrategy)is called - Reset/Initialization:
call!(s::SC, ::ResetStrategy)is called - Execution Loop:
call!(s::SC, timestamp, context)is called repeatedly - Cleanup:
call!(s::SC, ::StopStrategy)is called when stopping
Essential Strategy Methods
Required Methods
Optional Methods
Advanced Dispatch Patterns
Conditional Dispatch by Mode
Parameter-Based Dispatch
Advanced Examples
Multi-Timeframe Strategy
Portfolio Rebalancing Strategy
Advanced Optimization Strategy
Simple Moving Average Strategy
Margin Trading Strategy
Best Practices
Code Organization
Module Constants: Define strategy metadata at the top
Environment Macros: Use appropriate environment macros within your strategy module
Parameter Management: Use strategy attributes for parameters
Error Handling
Performance Optimization
- Minimize Allocations: Reuse data structures when possible
- Batch Operations: Group similar operations together
- Conditional Logic: Use early returns to avoid unnecessary computations
Testing and Validation
Strategy Configuration
Strategies can be configured through user/[planar.toml](../config.md#configuration-file):
[strategies.MyStrategy]
exchange = "binance"
margin = "NoMargin"
timeframe = "1h"
initial_cash = 10000.0
sandbox = true
[strategies.MyStrategy.attrs]
custom_param1 = 1.5
custom_param2 = "value"Quick Troubleshooting
For comprehensive strategy troubleshooting with detailed solutions, see Strategy Problems.
Common Issues Quick Reference
❌ Strategy loading fails → Strategy Problems: Loading Issues
- Module not found errors
- Compilation failures
- Missing dependencies
❌ Runtime execution errors → Strategy Problems: Execution Issues
- Method dispatch errors
- Data access problems
- Signal generation failures
❌ No trades executing → Strategy Problems: Order Execution
- Insufficient balance
- Order validation failures
- Position management errors
❌ Slow performance → Performance Issues
- Backtesting optimization
- Memory usage problems
- Algorithm efficiency
❌ Data problems → Exchange Issues or Performance Issues: Data
- Missing market data
- Exchange connectivity
- Database performance
Development Tips
Enable Debug Logging:
Test Components Individually:
Use Simulation Mode for Debugging:
For detailed troubleshooting steps and platform-specific solutions, visit Strategy Problems.es
- Check that
call!(s::SC, ::OptScore)returns appropriate metrics - Verify that parameter overrides are applied correctly in
call!(s::SC, params, ::OptRun)
Debugging Strategies
Enable Debug Logging
Strategy State Inspection
Performance Profiling
Removing Strategies
The function remove_strategy allows you to discard a strategy by its name:
Advanced Topics
Dynamic Universe Management
The universe (s.universe) is backed by a DataFrame (s.universe.data). It is possible to add and remove assets from the universe during runtime, although this feature is not extensively tested.
# Activate Planar project
import Pkg
Pkg.activate("Planar")
try
using Planar
@environment!
# Add new asset to universe (experimental)
function add_asset_to_universe_example(s, symbol::String)
# This requires careful handling of data synchronization
@info "Adding asset to universe: $symbol"
# Real implementation would be:
# new_asset = Asset(symbol, exchange(s))
# Careful handling of data synchronization required
println("Asset $symbol would be added to universe")
end
# Remove asset from universe (experimental)
function remove_asset_from_universe_example(s, symbol::String)
# Close any open positions first
@info "Removing asset from universe: $symbol"
# Real implementation would be:
# ai = s[symbol]
# if !isnothing(ai) && freecash(ai) != 0
# close_position(s, ai)
# end
println("Asset $symbol would be removed from universe")
end
println("Universe management functions defined (experimental)")
catch e
@warn "Planar not available: $e"
endCustom Indicators
Integration with External Libraries
This comprehensive guide provides everything you need to develop sophisticated trading strategies in Planar. Start with the basic examples and gradually work your way up to more advanced patterns as you become comfortable with the dispatch system and strategy architecture.