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.
Quick Navigation
- Strategy Fundamentals - Core concepts and architecture
- Creating Strategies - Interactive and manual setup
- Loading Strategies - Runtime instantiation
- 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
- 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 a New Strategy
Interactive Strategy Generator
The simplest way to create a strategy is using the interactive generator, which prompts for all required configuration options:
# Activate Planar project
import Pkg
Pkg.activate("Planar")
try
using Planar
# Example of strategy generation (interactive in real usage)
println("Strategy generation example:")
println("Strategy name: MyNewStrategy")
println("Available timeframes: 1m, 5m, 15m, 1h")
# Note: Planar.generate_strategy() is interactive and requires user input
# This example shows the expected output format
catch e
@warn "Planar module not fully available: $e"
end
1d
Select exchange by:
> volume
markets
nokyc
> binance
bitforex
okx
xt
coinbase
Quote currency:
USDT
USDC
> BTC
ETH
DOGE
Margin mode:
> NoMargin
Isolated
Activate strategy project at /path/to/Planar.jl/user/strategies/MyNewStrategy? [y]/n: y
Add project dependencies (comma separated): Indicators
Resolving package versions...
[...]
Activating project at `/path/to/Planar.jl/user/strategies/MyNewStrategy`
┌ Info: New Strategy
│ name = "MyNewStrategy"
│ [exchange](exchanges.md) = :binance
└ [timeframe](guides/../guides/data-management.md#timeframes) = "5m"
[ Info: Config file updated
Load strategy? [y]/n:
julia> s = ansNon-Interactive Strategy Creation
You can also create strategies programmatically without user interaction:
Loading a Strategy
Basic Strategy Loading
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)
After module import, the strategy is instantiated by calling call!(::Type{S}, ::LoadStrategy, cfg).
Strategy Type Structure
Example Strategy Module
Dispatch Convention
Rule of Thumb: Methods called before strategy construction dispatch on the strategy type (Type{<:S}), while methods called during runtime dispatch on the strategy instance (S).
Type Definitions:
S: Complete strategy type with all parameters (const S = Strategy{name, exc, ...})SC: Generic strategy type where exchange parameter is unspecified
Manual 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. The strategyProject.tomlis used to store strategy config options. See other strategies examples for what the keys that are required.
For more advanced setups you can also use Planar as a library, and construct the strategy object directly from your own module:
using Planar
using MyDownStreamModule
s = Planar.Engine.Strategies.strategy(MyDownStreamModule)Strategy Interface Details
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
List of strategy call! functions
Misc.call! — FunctionPlaces a limit order and synchronizes the cash balance.
call!(
s::Strategy{Misc.Live, N, <:ExchangeID, NoMargin, C} where {N, C},
ai,
t::Type{<:OrderTypes.Order{<:OrderTypes.LimitOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
price,
waitfor,
synced,
skipchecks,
kwargs...
)
This function initiates a limit order through the _live_limit_order function. Once the order is placed, it synchronizes the cash balance in the live strategy to reflect the transaction. It returns the trade information once the transaction is complete.
Places a market order and synchronizes the cash balance.
call!(
s::Strategy{Misc.Live, N, <:ExchangeID, NoMargin, C} where {N, C},
ai,
t::Type{<:OrderTypes.Order{<:OrderTypes.MarketOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
waitfor,
synced,
skipchecks,
kwargs...
)
This function initiates a market order through the _live_market_order function. Once the order is placed, it synchronizes the cash balance in the live strategy to reflect the transaction. It returns the trade information once the transaction is complete.
Cancels all live orders of a certain type and synchronizes the cash balance.
call!(
s::Strategy{Misc.Live},
ai::Instances.AssetInstance,
::Executors.CancelOrders;
t,
waitfor,
confirm,
synced,
ids
) -> Bool
This function cancels all live orders of a certain side (buy/sell) through the live_cancel function. Once the orders are canceled, it waits for confirmation of the cancelation and then synchronizes the cash balance in the live strategy to reflect the cancelations. It returns a boolean indicating whether the cancellation was successful.
Updates leverage or places an order in a live trading strategy.
call!(
s::Strategy{Misc.Live, N, <:ExchangeID, <:Misc.WithMargin, C} where {N, C},
ai::Instances.AssetInstance{<:AbstractAsset, <:ExchangeID, M} where M<:Misc.WithMargin,
lev,
::Executors.UpdateLeverage;
pos,
synced,
atol,
force
)
This function either updates the leverage of a position or places an order in a live trading strategy. It first checks if the position is open or has pending orders. If not, it updates the leverage on the exchange and then synchronizes the position. If an order is to be placed, it checks for any open positions on the opposite side and places the order if none exist. The function returns the trade or leverage update status.
Executes a limit order in a live trading strategy.
call!(
s::Strategy{Misc.Live, N, <:ExchangeID, Isolated, C} where {N, C},
ai::Instances.AssetInstance{<:AbstractAsset, <:ExchangeID, M} where M<:Misc.WithMargin,
t::Type{<:OrderTypes.Order{<:OrderTypes.LimitOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
price,
waitfor,
skipchecks,
synced,
kwargs...
)
This function executes a limit order in a live trading strategy, given a strategy s, an asset instance ai, and a trade type t. It checks for open positions on the opposite side and places the order if none exist. The function returns the trade or leverage update status.
Executes a market order in a live trading strategy.
call!(
s::Strategy{Misc.Live, N, <:ExchangeID, Isolated, C} where {N, C},
ai::Instances.AssetInstance{<:AbstractAsset, <:ExchangeID, M} where M<:Misc.WithMargin,
t::Type{<:OrderTypes.Order{<:OrderTypes.MarketOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
waitfor,
skipchecks,
synced,
kwargs...
)
This function executes a market order in a live trading strategy, given a strategy s, an asset instance ai, and a trade type t. It checks for open positions on the opposite side and places the order if none exist. The function returns the trade or leverage update status.
Closes a leveraged position in a live trading strategy.
call!(
s::Strategy{Misc.Live, N, <:ExchangeID, <:Misc.WithMargin, C} where {N, C},
ai::Instances.AssetInstance{<:AbstractAsset, <:ExchangeID, M} where M<:Misc.WithMargin,
::Union{Type{P<:Misc.PositionSide}, Type{O} where O<:(OrderTypes.Order{<:OrderTypes.OrderType, <:AbstractAsset, <:ExchangeID, P<:Misc.PositionSide}), Type{T} where T<:(OrderTypes.Trade{<:OrderTypes.OrderType, <:AbstractAsset, <:ExchangeID, P<:Misc.PositionSide}), OrderTypes.Order{<:OrderTypes.OrderType, <:AbstractAsset, <:ExchangeID, P<:Misc.PositionSide}, OrderTypes.Trade{<:OrderTypes.OrderType, <:AbstractAsset, <:ExchangeID, P<:Misc.PositionSide}, P<:Misc.PositionSide},
date,
::Instances.PositionClose;
t,
waitfor,
kwargs...
) -> Bool
This function cancels any pending orders and checks the position status. If the position is open, it places a closing trade and waits for it to be executed. The function returns true if the position is successfully closed, false otherwise.
Executes the OHLCV watcher for a real-time strategy.
call!(
s::RTStrategy,
::Executors.WatchOHLCV,
args...;
kwargs...
)
This function triggers the execution of the OHLCV (Open, High, Low, Close, Volume) watcher for a real-time strategy s.
Triggers the data update for a real-time strategy.
call!(
f::Function,
s::RTStrategy,
::Executors.UpdateData;
cols,
timeframe
)
This function initiates the update of data for a real-time strategy s. The update is performed for the specified columns cols and uses the provided timeframe timeframe.
Triggers the data update for an asset instance in a real-time strategy.
call!(
f::Function,
s::RTStrategy,
ai::Instances.AssetInstance,
::Executors.UpdateData;
cols,
timeframe
)
This function triggers the update of data for a specific asset instance ai in a real-time strategy s. The update is performed for the specified columns cols and uses the provided timeframe timeframe.
Initializes the data for a real-time strategy.
call!(
f::Function,
s::RTStrategy,
::Executors.InitData;
cols,
timeframe
)
This function initializes the data for a real-time strategy s. The initialization is performed for the specified columns cols and uses the provided timeframe timeframe. After the initialization, the updated_at! function is called to update the timestamp for the updated columns.
Called on each timestep iteration, possible multiple times. Receives:
current_time: the current timestamp to evaluate (the current candle would becurrent_time - timeframe).ctx: The context of the executor.
call!(_::Strategy, current_time::Dates.DateTime, ctx)
Called to construct the strategy, should return the strategy instance.
call!(_::Type{<:Strategy}, cfg, _::LoadStrategy)
Called at the end of the reset! function applied to a strategy.
call!(_::Strategy, _::ResetStrategy)
How much lookback data the strategy needs.
call!(s::Strategy, _::WarmupPeriod) -> Any
When an order is canceled the strategy is pinged with an order error.
call!(
s::Strategy,
::OrderTypes.Order,
err::OrderTypes.OrderError,
::Instances.AssetInstance;
kwargs...
) -> Any
Market symbols that populate the strategy universe
Called before the strategy is started.
call!(_::Strategy, _::StartStrategy)
Called after the strategy is stopped.
call!(_::Strategy, _::StopStrategy)
Creates a simulated limit order.
call!(
s::SimStrategy{N, <:ExchangeID, NoMargin, C} where {N, C},
ai,
t::Type{<:OrderTypes.Order{<:OrderTypes.LimitOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
kwargs...
)
The function call! is responsible for creating a simulated limit order. It creates the order using create_sim_limit_order, checks if the order is not nothing, and then calls limitorder_ifprice!. The parameters include a strategy s, an asset ai, and a type t. The function also accepts an amount and additional arguments kwargs....
Creates a simulated market order.
call!(
s::SimStrategy{N, <:ExchangeID, NoMargin, C} where {N, C},
ai,
t::Type{<:OrderTypes.Order{<:OrderTypes.MarketOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
date,
kwargs...
)
The function call! creates a simulated market order using create_sim_market_order. It checks if the order is not nothing, and then calls marketorder!. Parameters include a strategy s, an asset ai, a type t, an amount and a date. Additional arguments can be passed through kwargs....
Cancel orders for a specific asset instance.
call!(
s::Strategy{<:Union{Misc.Paper, Misc.Sim}},
ai::Instances.AssetInstance,
::Executors.CancelOrders;
t,
kwargs...
) -> Bool
The function call! cancels all orders for a specific asset instance ai. It iterates over the orders of the asset and cancels each one using cancel!. Parameters include a strategy s, an asset instance ai, and a type t which defaults to BuyOrSell. Additional arguments can be passed through kwargs....
After a position was updated from a trade.
call!(
_::Strategy{X, N, <:ExchangeID, <:Misc.WithMargin, C} where {X<:Misc.ExecMode, N, C},
ai,
trade::OrderTypes.Trade,
_::Instances.Position,
_::Instances.PositionChange
)
This function is called after a position is updated due to a trade. It takes in a MarginStrategy, ai, trade, Position, and PositionChange as arguments. The function does not return any value.
After a position update from a candle.
call!(
_::Strategy{X, N, <:ExchangeID, <:Misc.WithMargin, C} where {X<:Misc.ExecMode, N, C},
ai,
date::Dates.DateTime,
_::Instances.Position,
_::Instances.PositionUpdate
)
This function is called after a position is updated from a candle. It provides the necessary functionality for handling position updates in response to candle data.
Creates a simulated limit order, updating a levarged position.
"Creates a simulated market order, updating a levarged position.
Usually an exchange checks before executing a trade if right after the trade the position would be liquidated, and would prevent you to do such trade, however we always check after the trade, and liquidate accordingly, this is pessimistic since we can't ensure that all exchanges have such protections in place.
Closes a leveraged position.
Closes all strategy positions
Update position leverage. Returns true if the update was successful, false otherwise.
The leverage is not updated when the position has pending orders or is open (and it will return false in such cases.)
Watchers are not used in SimMode.
Data should be pre initialized in SimMode.
Data should be pre initialized in SimMode.
Data should be pre initialized in SimMode.
Initialize data for each asset in the strategy.
call!(
f::Function,
s::SimStrategy,
::Executors.InitData;
cols,
timeframe
)
This function initializes data for each asset in the strategy by retrieving the OHLCV data and setting the specified columns.
Creates a paper market order.
call!(
s::Strategy{Misc.Paper, N, <:ExchangeID, NoMargin, C} where {N, C},
ai,
t::Type{<:OrderTypes.Order{<:OrderTypes.MarketOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
date,
price,
kwargs...
)
The function creates a paper market order for a given strategy and asset. It specifies the amount of the order and the type of order (e.g., limit order, immediate order).
Creates a simulated limit order.
call!(
s::Strategy{Misc.Paper, N, <:ExchangeID, NoMargin, C} where {N, C},
ai,
t::Type{<:OrderTypes.Order{<:OrderTypes.LimitOrderType}};
amount,
date,
kwargs...
)
The function creates a simulated limit order for a given strategy and asset. It specifies the amount of the order and the date. Additional keyword arguments can be passed.
Creates a paper market order, updating a leveraged position.
call!(
s::Strategy{Misc.Paper, N, <:ExchangeID, Isolated, C} where {N, C},
ai::Instances.AssetInstance{<:AbstractAsset, <:ExchangeID, M} where M<:Misc.WithMargin,
t::Type{<:OrderTypes.Order{<:OrderTypes.MarketOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
date,
price,
kwargs...
)
The function creates a paper market order for a given strategy, asset, and order type. It specifies the amount and date of the order. Additional keyword arguments can be passed.
Creates a simulated limit order.
call!(
s::Strategy{Misc.Paper, N, <:ExchangeID, Isolated, C} where {N, C},
ai,
t::Type{<:OrderTypes.Order{<:OrderTypes.LimitOrderType{S}, <:AbstractAsset, <:ExchangeID, P} where {S<:OrderTypes.OrderSide, P<:Misc.PositionSide}};
amount,
date,
kwargs...
)
The function creates a simulated limit order for a given strategy, asset, and order type. It specifies the amount and date of the order. Additional keyword arguments can be passed.
Closes positions for a live margin strategy.
call!(
s::RTStrategy{var"#s1941", N, <:ExchangeID, <:Misc.WithMargin, C} where {var"#s1941"<:Union{Misc.Live, Misc.Paper}, N, C},
bp::OrderTypes.ByPos,
date,
::Instances.PositionClose;
kwargs...
)
Initiates asynchronous position closing for each asset instance in the strategy's universe.
Returns Optim.ContextSpace for backtesting
call!(_::Strategy, _::Executors.OptSetup)
The ctx field (Executors.Context) specifies the backtest time period, while bounds is a tuple of (lower, upper) bounds for the optimization parameters.
Applies parameters to strategy before backtest
call!(_::Strategy, params, _::Executors.OptRun)
Indicates if the optimization is a minimization problem.
call!(_::Strategy, _::Executors.OptMinimize) -> Bool
Initializes warmup attributes for a strategy.
call!(
s::Strategy,
::InitSimWarmup;
timeout,
warmup_period
) -> Any
Initiates the warmup process for a real-time strategy instance.
call!(
cb::Function,
s::RTStrategy,
ai::Instances.AssetInstance,
ats::Dates.DateTime,
::SimWarmup;
n_candles
)
If warmup has not been previously completed for the given asset instance, it performs the necessary preparations.
Initiates the warmup process for all assets in the universe for a simulation strategy.
call!(cb::Function, s::SimStrategy, ::SimWarmup; n_candles)
Runs warmup simulation on all assets in the strategy's universe simultaneously.
Initiates the warmup process for all assets in the universe for a real-time strategy.
call!(
cb::Function,
s::RTStrategy,
ats::Dates.DateTime,
::SimWarmup;
n_candles
)
Runs warmup simulation on all assets in the strategy's universe simultaneously.
Removing a strategy
The function remove_strategy allows to discard a strategy by its name. It will delete the julia file or the project directory and optionally the config entry.
julia> Planar.remove_strategy("MyNewStrategy")
Really delete strategy located at /run/media/fra/stateful-1/dev/Planar.jl/user/strategies/MyNewStrategy? [n]/y: y
[ Info: Strategy removed
Remove user config entry MyNewStrategy? [n]/y: yAdvanced Strategy Examples
Multi-Timeframe Strategy
Portfolio Rebalancing Strategy
Advanced Optimization Strategy
Strategy Setup and Loading (Preserved)
Strategy examples can be found in the user/strategies folder. Some strategies are single files like Example.jl while strategies like BollingerBands or ExampleMargin are project-based.
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 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"Strategy Examples
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
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
Resizeable Universe
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.
Dynamic Asset Management
Troubleshooting and Debugging
Common Strategy Issues
1. Strategy Loading Problems
Issue: Strategy fails to load with module not found error
Solutions:
- Verify the strategy file exists in
user/strategies/ - Check that the module name matches the file name
- Ensure the strategy module is properly defined:
Issue: Strategy loads but crashes during initialization
Solutions:
- Add the
@strategyenv!macro to import required types - Verify all required constants are defined:
2. Data Access Issues
Issue: OHLCV data is empty or missing
Solutions:
- Check data availability for your timeframe and date range
- Verify exchange supports the requested markets
- Ensure sufficient warmup period:
Issue: Inconsistent data between timeframes
Solutions:
- Use
available()function to get valid timestamps - Handle missing data gracefully:
3. Order Execution Problems
Issue: Orders are rejected with insufficient funds
Solutions:
- Check available cash before placing orders:
Issue: Orders fail due to minimum size requirements
Solutions:
- Check exchange limits before placing orders:
4. Margin Trading Issues
Issue: Leverage updates fail
Solutions:
- Check exchange-specific leverage limits
- Update leverage before placing orders:
Debugging Techniques
1. Logging and Monitoring
2. Strategy State Inspection
3. Performance Profiling
4. Unit Testing Strategies
Error Recovery Patterns
1. Graceful Degradation
2. Circuit Breaker Pattern
Performance Optimization Tips
- Minimize Data Access: Cache frequently used values
- Batch Operations: Group similar operations together
- Use Type Stability: Ensure functions return consistent types
- Profile Regularly: Use Julia's profiling tools to identify bottlenecks
- Memory Management: Avoid unnecessary allocations in hot paths
der Management and Risk Control
Order Types and Execution
Planar supports various order types for different trading scenarios. Understanding when and how to use each type is crucial for effective strategy implementation.
Market Orders
Market orders execute immediately at the current market price:
Limit Orders
Limit orders execute only at a specified price or better:
Stop Orders
Stop orders become market orders when a trigger price is reached:
Order Management Patterns
Position Management for Margin Trading
Position Types and States
Leverage Management
Position Sizing Strategies
Risk Management Patterns
Stop Loss Strategies
Take Profit Strategies
Portfolio Risk Management
Risk Metrics and Monitoring
This comprehensive order management and risk documentation provides practical patterns for implementing robust trading strategies with proper risk controls.
Se
e Also
Core Documentation
- Data Management - Working with OHLCV data and storage
- Execution Modes - Understanding Sim, Paper, and Live modes
- Optimization - Parameter optimization and backtesting
- Plotting - Visualizing strategy performance and results
Advanced Topics
- Customization Guide - Extending Planar's functionality
- Custom Orders - Implementing custom order types
- Exchange Extensions - Adding new exchange support
API Reference
- Strategy API - Complete strategy function reference
- Engine API - Core engine functions
- Strategy Tools - Utility functions for strategies
- Strategy Stats - Performance analysis functions
Support
- Troubleshooting - Common strategy development issues
- Community - Getting help and sharing strategies
Next Steps
After mastering strategy development:
- Optimize Your Strategies - Learn parameter optimization techniques
- Visualize Performance - Create compelling performance charts
- Deploy Live - Move from backtesting to live trading
- Extend Functionality - Customize Planar for your needs