Optimization in Pine Script
Strategy optimization helps find the best parameters for your trading strategies. This guide covers optimization techniques and avoiding common pitfalls.
Why Optimize?
Benefit Description Better performance Find optimal parameters Adaptability Adjust to market conditions Robustness Create resilient strategies Efficiency Maximize risk-adjusted returns
Basic Optimization
Enable Optimization
//@version=6
strategy("Optimize Strategy",
overlay=true,
optimize=true) // Enable optimization
// Optimizable parameters
fastMA = input.int(12, "Fast MA", 5, 50, 1)
slowMA = input.int(26, "Slow MA", 10, 100, 5)
rsiLevel = input.int(30, "RSI Level", 20, 40, 5)
// Strategy logic
fast = ta.ema(close, fastMA)
slow = ta.ema(close, slowMA)
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
strategy.close("Long")
plot(fast)
plot(slow)
Multiple Parameters
//@version=6
strategy("Multi Optimize",
overlay=true,
optimize=true)
// MA Parameters
maType = input.string("EMA", "MA Type", options=["SMA", "EMA", "WMA"])
maLength = input.int(20, "MA Length", 10, 100, 5)
// RSI Parameters
rsiLength = input.int(14, "RSI", 7, 21, 1)
rsiOS = input.int(30, "Oversold", 20, 40, 5)
rsiOB = input.int(70, "Overbought", 60, 80, 5)
// ATR Parameters
atrLength = input.int(14, "ATR", 7, 28, 1)
atrMult = input.float(2.0, "ATR Mult", 1.5, 3.0, 0.5)
// Strategy logic
ma = maType == "SMA" ? ta.sma(close, maLength) : ta.ema(close, maLength)
rsi = ta.rsi(close, rsiLength)
atr = ta.atr(atrLength)
longCondition = ta.crossover(close, ma) and rsi < rsiOS
shortCondition = ta.crossunder(close, ma) and rsi > rsiOB
if longCondition
strategy.entry("Long", strategy.long)
if shortCondition
strategy.entry("Short", strategy.short)
if ta.crossunder(close, ma)
strategy.close_all()
plot(ma)
Common Parameters to Optimize
Moving Average Periods
//@version=6
strategy("MA Optimizer",
overlay=true,
optimize=true)
fastLength = input.int(10, "Fast", 5, 30, 1)
medLength = input.int(30, "Medium", 20, 60, 5)
slowLength = input.int(100, "Slow", 50, 200, 10)
fastMA = ta.ema(close, fastLength)
medMA = ta.ema(close, medLength)
slowMA = ta.ema(close, slowLength)
if ta.crossover(medMA, slowMA) and close > fastMA
strategy.entry("Long", strategy.long)
if ta.crossunder(medMA, slowMA)
strategy.close_all()
plot(fastMA)
plot(medMA)
plot(slowMA)
RSI Parameters
//@version=6
strategy("RSI Optimizer",
overlay=false,
optimize=true)
rsiLen = input.int(14, "Length", 7, 28, 1)
oversold = input.int(30, "Oversold", 20, 40, 5)
overbought = input.int(70, "Overbought", 60, 80, 5)
rsi = ta.rsi(close, rsiLen)
if ta.crossover(rsi, oversold)
strategy.entry("Long", strategy.long)
if ta.crossunder(rsi, overbought)
strategy.close_all()
plot(rsi)
hline(overbought)
hline(oversold)
Stop Loss / Take Profit
//@version=6
strategy("SL/TP Optimizer",
overlay=true,
optimize=true)
atrLength = input.int(14, "ATR")
slMultiplier = input.float(2.0, "SL ATR", 1.0, 4.0, 0.5)
tpMultiplier = input.float(3.0, "TP ATR", 1.0, 6.0, 0.5)
atr = ta.atr(atrLength)
if ta.crossover(ta.ema(close, 12), ta.ema(close, 26))
strategy.entry("Long", strategy.long)
strategy.exit("SL/TP", "Long",
stop=close - atr * slMultiplier,
limit=close + atr * tpMultiplier)
plot(ta.ema(close, 12))
plot(ta.ema(close, 26))
Optimization Best Practices
1. Start Simple
// GOOD: Few parameters
fastMA = input.int(12, "Fast")
slowMA = input.int(26, "Slow")
// BAD: Too many parameters
p1 = input(1)
p2 = input(2)
p3 = input(3)
p4 = input(4)
p5 = input(5)
p6 = input(6)
2. Use Realistic Ranges
// GOOD: Realistic ranges
fastMA = input.int(12, "Fast", 5, 30, 1) // Common values
// BAD: Unrealistic ranges
fastMA = input.int(12, "Fast", 1, 500, 1) // Too broad
3. Test Multiple Markets
// Test your optimized strategy on:
// - Different forex pairs
// - Different stocks
// - Different timeframes
// - Different market conditions
Walk Forward Optimization
Rolling Optimization
//@version=6
strategy("Walk Forward",
overlay=true,
optimize=true)
// Use recent data for optimization
lookback = 200
trainLength = 150
testLength = 50
// Example parameter
maLength = input.int(20, "MA", 10, 50, 5)
if bar_index > lookback
ma = ta.sma(close, maLength)
if ta.crossover(close, ma)
strategy.entry("Long", strategy.long)
if ta.crossunder(close, ma)
strategy.close("Long")
plot(ta.sma(close, maLength))
Metrics to Optimize
Primary Metrics
Metric Target Net Profit High Profit Factor > 1.5 Sharpe Ratio > 1.0 Max Drawdown < 20% Win Rate > 40%
Secondary Metrics
Metric Target Avg Trade > 0 Avg Win/Loss > 1.5 Recovery Factor > 2.0 Expectancy > 0.5R
Avoiding Overfitting
Signs of Overfitting
Works perfectly on backtest
Fails in live trading
Many parameters
Perfect curve fitting
No out-of-sample testing
Prevention
// GOOD: Simple, robust
maLength = input.int(20, "Length", 10, 50, 5)
// GOOD: Limited parameters
// 2-3 main parameters
// GOOD: Out-of-sample testing
// Reserve 20% of data for testing
Robustness Testing
Monte Carlo Analysis
// Run strategy multiple times with:
// - Different random entry times
// - Different slippage
// - Different commission
Sensitivity Analysis
// Test parameter stability:
// If optimal is 20, test 15-25
// Strategy should perform similarly
Market Conditions
// Test in:
// - Trending markets
// - Ranging markets
// - High volatility
// - Low volatility
// - News events
Complete Optimizable Strategy
//@version=6
strategy("Complete Optimizable",
overlay=true,
default_qty_type=strategy.percent_of_equity,
default_qty_value=10,
optimize=true)
// === INPUTS ===
maFast = input.int(12, "Fast MA", 5, 30, 1)
maSlow = input.int(26, "Slow MA", 15, 60, 5)
rsiLen = input.int(14, "RSI", 7, 21, 1)
rsiOS = input.int(30, "RSI OS", 20, 40, 5)
rsiOB = input.int(70, "RSI OB", 60, 80, 5)
atrLen = input.int(14, "ATR")
slMult = input.float(2.0, "SL ATR", 1.0, 4.0, 0.5)
tpMult = input.float(3.0, "TP ATR", 1.0, 6.0, 0.5)
// === CALCULATIONS ===
maF = ta.ema(close, maFast)
maS = ta.ema(close, maSlow)
rsi = ta.rsi(close, rsiLen)
atr = ta.atr(atrLen)
// === SIGNALS ===
longSignal = ta.crossover(maF, maS) and rsi < rsiOS
shortSignal = ta.crossunder(maF, maS) and rsi > rsiOB
// === ENTRIES ===
if longSignal
strategy.entry("Long", strategy.long)
if shortSignal
strategy.entry("Short", strategy.short)
// === EXITS ===
if strategy.position_size > 0
strategy.exit("Long Exit", "Long",
stop=close - atr * slMult,
limit=close + atr * tpMult)
if strategy.position_size < 0
strategy.exit("Short Exit", "Short",
stop=close + atr * slMult,
limit=close - atr * tpMult)
// === PLOT ===
plot(maF, color=color.green)
plot(maS, color=color.red)
Optimization Workflow
Define hypothesis - What should work?
Start simple - Few parameters
Optimize - Find best values
Validate - Test on out-of-sample
Test robustness - Different conditions
Paper trade - Live simulation
Deploy - Small capital
Monitor - Track performance
Next Steps
backtesting - Proper backtesting
stops - Advanced stops
Build and test your strategies
Optimize wisely - avoid overfitting.