Quant.Strategy.Optimization (quant v0.1.0-alpha.1)
Parameter optimization engine for systematic strategy tuning.
This module provides vectorbt-like functionality for testing parameter combinations and finding optimal strategy configurations.
Features
- Single and multi-parameter optimization
- Parallel processing for efficient computation
- Comprehensive result analysis and ranking
- Walk-forward optimization for robust validation
- Integration with all existing strategy types
Basic Usage
# Simple parameter sweep
{:ok, df} = Quant.Explorer.history("AAPL", provider: :yahoo_finance, period: "1y")
param_ranges = %{fast_period: 5..20, slow_period: 20..50}
{:ok, results} = Quant.Strategy.Optimization.run_combinations(df, :sma_crossover, param_ranges)
# Find best parameters
best = Quant.Strategy.Optimization.find_best_params(results, :total_return)Parallel Processing
# Use all available cores
{:ok, results} = Quant.Strategy.Optimization.run_combinations_parallel(
df, :sma_crossover, param_ranges, concurrency: System.schedulers_online()
)
Summary
Functions
Analyze parameter sensitivity across results.
Find the best parameter combination based on a specific metric.
Generate parameter heatmap data for visualization.
Run parameter combinations for a single strategy type.
Run parameter combinations using parallel processing.
Run parameter combinations using memory-efficient streaming.
Analyze parameter stability across different metrics.
Perform walk-forward optimization with rolling windows.
Types
@type optimization_result() :: {:ok, Explorer.DataFrame.t()} | {:error, term()}
@type strategy_type() :: atom()
Functions
@spec analyze_parameter_sensitivity(Explorer.DataFrame.t(), atom()) :: {:ok, map()} | {:error, term()}
Analyze parameter sensitivity across results.
Shows how changes in a specific parameter affect performance metrics.
Examples
# See how fast_period affects returns
sensitivity = analyze_parameter_sensitivity(results, :fast_period)
@spec find_best_params(Explorer.DataFrame.t(), atom()) :: map() | nil
Find the best parameter combination based on a specific metric.
Parameters
results- DataFrame from optimization resultsmetric- Metric to optimize for (default: :total_return)
Available Metrics
:total_return- Total portfolio return:sharpe_ratio- Risk-adjusted return:sortino_ratio- Downside deviation adjusted return:calmar_ratio- Return divided by max drawdown:win_rate- Percentage of winning trades:profit_factor- Gross profit divided by gross loss
Examples
# Find best total return
best = find_best_params(results, :total_return)
# Find best risk-adjusted return
best = find_best_params(results, :sharpe_ratio)
@spec parameter_heatmap(Explorer.DataFrame.t(), atom(), atom(), atom()) :: {:ok, Explorer.DataFrame.t()} | {:error, term()}
Generate parameter heatmap data for visualization.
Creates a 2D heatmap showing how a performance metric varies across two parameter dimensions.
Parameters
results- Optimization results DataFramex_param- Parameter for X-axisy_param- Parameter for Y-axismetric- Performance metric to visualize
Examples
# Create heatmap of total return vs fast/slow periods
heatmap = parameter_heatmap(results, :fast_period, :slow_period, :total_return)
@spec run_combinations( Explorer.DataFrame.t(), strategy_type(), param_ranges(), optimization_options() ) :: optimization_result()
Run parameter combinations for a single strategy type.
Tests all combinations of the provided parameter ranges and returns optimization results as a DataFrame.
Parameters
dataframe- Historical OHLCV datastrategy_type- Strategy type atom (e.g., :sma_crossover, :rsi_threshold)param_ranges- Map of parameter names to ranges or lists of valuesopts- Optimization options
Options
:initial_capital- Starting capital (default: 10000.0):commission- Trading commission rate (default: 0.001):slippage- Market slippage rate (default: 0.0005):store_backtest_data- Whether to store full backtest results (default: false)
Examples
# Test SMA crossover periods
param_ranges = %{fast_period: 5..15, slow_period: 20..40}
{:ok, results} = run_combinations(df, :sma_crossover, param_ranges)
# Test with custom options
{:ok, results} = run_combinations(df, :sma_crossover, param_ranges,
initial_capital: 50_000.0,
commission: 0.002
)
@spec run_combinations_parallel( Explorer.DataFrame.t(), strategy_type(), param_ranges(), optimization_options() ) :: optimization_result()
Run parameter combinations using parallel processing.
Same as run_combinations/4 but processes parameter combinations
concurrently for improved performance.
Additional Options
:concurrency- Number of parallel tasks (default: System.schedulers_online()):progress_callback- Function called with progress percentage:timeout- Timeout per parameter combination in ms (default: 30_000)
Examples
# Use all CPU cores
{:ok, results} = run_combinations_parallel(df, :sma_crossover, param_ranges,
concurrency: System.schedulers_online()
)
# With progress tracking
progress_fn = fn progress -> IO.puts("Progress: " <> Integer.to_string(progress) <> "%") end
{:ok, results} = run_combinations_parallel(df, :sma_crossover, param_ranges,
progress_callback: progress_fn
)
@spec run_combinations_stream( Explorer.DataFrame.t(), strategy_type(), param_ranges(), optimization_options() ) :: Enumerable.t()
Run parameter combinations using memory-efficient streaming.
Processes massive parameter spaces (10,000+ combinations) in chunks without loading all results into memory simultaneously. Returns a stream of result chunks for further processing.
Parameters
dataframe- Historical OHLCV datastrategy_type- Strategy type atomparam_ranges- Map of parameter names to ranges or listsopts- Streaming options
Streaming Options
:chunk_size- Combinations per chunk (default: 100):concurrency- Parallel tasks per chunk (default: 4):timeout- Timeout per chunk in ms (default: 30_000):memory_limit- Max memory usage in MB (default: 500)
Returns
Stream of {:ok, chunk_results_df} or {:error, reason}
Examples
# Stream massive parameter space
param_ranges = %{period: 1..100, threshold: 0.01..0.10//0.01} # 10,000 combos
stream = run_combinations_stream(df, :sma_crossover, param_ranges, chunk_size: 50)
# Process results incrementally
best_result =
stream
|> Stream.filter(fn {:ok, _chunk} -> true; _ -> false end)
|> Stream.map(fn {:ok, chunk} -> Results.find_best_params(chunk) end)
|> Enum.max_by(fn result -> result.total_return end)
# Export results as they come
stream
|> Stream.each(fn {:ok, chunk} -> export_chunk_to_csv(chunk) end)
|> Stream.run()
@spec stability_analysis(Explorer.DataFrame.t(), atom(), float()) :: {:ok, map()} | {:error, term()}
Analyze parameter stability across different metrics.
Identifies parameter combinations that perform consistently well across multiple performance metrics.
Parameters
results- Optimization resultsmetric- Primary metric to analyzethreshold- Stability threshold (default: 0.1)
Examples
# Find stable parameter combinations
stability = stability_analysis(results, :total_return, 0.15)
@spec walk_forward_optimization( Explorer.DataFrame.t(), strategy_type(), param_ranges(), keyword() ) :: optimization_result()
Perform walk-forward optimization with rolling windows.
Tests parameter stability over time by optimizing on a training window and testing on a subsequent period, then rolling forward.
Parameters
dataframe- Long-term historical datastrategy_type- Strategy to optimizeparam_ranges- Parameter ranges to testopts- Walk-forward options
Walk-Forward Options
:training_window- Size of training period in days (default: 252):testing_window- Size of testing period in days (default: 63):step_size- Days to step forward each iteration (default: 21):min_trades- Minimum trades required for valid result (default: 5)
Examples
# Annual training, quarterly testing, monthly steps
{:ok, wf_results} = walk_forward_optimization(df, :sma_crossover, param_ranges,
training_window: 252,
testing_window: 63,
step_size: 21
)