Skip to content

Standard Deviation (STDDEV)

Standard Deviation measures the dispersion or volatility of price returns around their mean. It quantifies how much prices deviate from their average value, making it essential for volatility analysis, risk management, and position sizing. Higher standard deviation indicates greater volatility and price swings, while lower values suggest more stable price action.

Usage

require 'sqa/tai'

prices = [44.34, 44.09, 44.15, 43.61, 44.33, 44.83,
          45.10, 45.42, 45.84, 46.08, 46.03, 46.41,
          46.22, 45.64, 46.21, 46.25, 46.08, 46.46,
          46.57, 45.95, 46.50, 46.02]

# Calculate 20-period standard deviation
stddev = SQA::TAI.stddev(prices, period: 20, nbdev: 1.0)

puts "Current Volatility: #{stddev.last.round(4)}"

Parameters

Parameter Type Required Default Description
prices Array Yes - Array of price values
period Integer No 5 Number of periods for calculation
nbdev Float No 1.0 Number of standard deviations (multiplier)

Returns

Returns an array of standard deviation values. The first period - 1 values will be nil. Values are scaled by nbdev parameter.

Interpretation

STDDEV Value Market Condition Trading Implication
High/Rising High volatility Wide price swings, larger stops, breakout potential
Low/Falling Low volatility Tight range, squeeze pattern, consolidation
Expanding Volatility increasing Trend acceleration, breakout occurring
Contracting Volatility decreasing Range compression, pre-breakout squeeze

Note: Array elements should be ordered from oldest to newest (chronological order)

Example: Volatility Regime Detection

prices = load_historical_prices('AAPL')

stddev = SQA::TAI.stddev(prices, period: 20, nbdev: 1.0)
current_vol = stddev.last

# Calculate volatility percentile
recent_vols = stddev.last(100).compact
percentile = recent_vols.count { |v| v < current_vol } / recent_vols.size.to_f * 100

puts "Current Volatility: #{current_vol.round(4)}"
puts "Volatility Percentile: #{percentile.round(1)}%"

case percentile
when 0...20
  puts "Low Volatility Regime - Expect breakout soon"
  puts "Strategy: Prepare for range expansion"
when 20...40
  puts "Below Average Volatility"
  puts "Strategy: Look for squeeze setups"
when 40...60
  puts "Normal Volatility"
  puts "Strategy: Standard position sizing"
when 60...80
  puts "Above Average Volatility"
  puts "Strategy: Reduce position size"
when 80..100
  puts "High Volatility Regime - Exercise caution"
  puts "Strategy: Smaller positions, wider stops"
end

Example: Dynamic Position Sizing

prices = load_historical_prices('TSLA')

stddev = SQA::TAI.stddev(prices, period: 20, nbdev: 1.0)
current_price = prices.last
current_vol = stddev.last

# Risk-based position sizing
account_size = 100_000
risk_per_trade = 0.02  # 2% risk
max_position = account_size * 0.10  # Max 10% per position

# Stop loss at 2 standard deviations
stop_distance = current_vol * 2
stop_price = current_price - stop_distance
risk_per_share = stop_distance

# Calculate position size based on volatility
shares = (account_size * risk_per_trade) / risk_per_share
position_value = shares * current_price

# Cap at maximum position size
if position_value > max_position
  shares = max_position / current_price
  position_value = max_position
end

puts <<~POSITION_SIZING
  === Volatility-Based Position Sizing ===
  Current Price: $#{current_price.round(2)}
  Standard Deviation: $#{current_vol.round(2)}
  Stop Loss (2 SD): $#{stop_price.round(2)}
  Risk per Share: $#{risk_per_share.round(2)}

  Recommended Shares: #{shares.round(0)}
  Position Value: $#{position_value.round(2)}
  Max Risk: $#{(shares * risk_per_share).round(2)}
POSITION_SIZING

Example: Volatility Squeeze Detection

prices = load_historical_prices('MSFT')

stddev = SQA::TAI.stddev(prices, period: 20, nbdev: 1.0)

# Calculate Bollinger Band width using standard deviation
upper, middle, lower = SQA::TAI.bbands(prices, period: 20, nbdev_up: 2.0, nbdev_down: 2.0)
bandwidth = (upper.last - lower.last) / middle.last * 100

# Compare current volatility to recent range
recent_stddevs = stddev.last(100).compact
min_vol = recent_stddevs.min
max_vol = recent_stddevs.max
avg_vol = recent_stddevs.sum / recent_stddevs.size
current_vol = stddev.last

# Squeeze detection
vol_range = max_vol - min_vol
vol_position = (current_vol - min_vol) / vol_range * 100

puts "=== Volatility Squeeze Analysis ==="
puts "Current STDDEV: #{current_vol.round(4)}"
puts "Average STDDEV: #{avg_vol.round(4)}"
puts "Volatility Position: #{vol_position.round(1)}% of range"
puts "Bollinger Bandwidth: #{bandwidth.round(2)}%"

if vol_position < 25 && bandwidth < 10
  puts "\n*** SQUEEZE ALERT ***"
  puts "Extremely low volatility detected"
  puts "Prepare for significant breakout"
  puts "Watch for direction confirmation"
elsif vol_position > 75
  puts "\nHigh Volatility - Trend in motion"
  puts "Consider trailing stops"
end

Example: Volatility Breakout Strategy

prices = load_historical_prices('NVDA')
highs = load_historical_highs('NVDA')
lows = load_historical_lows('NVDA')

stddev = SQA::TAI.stddev(prices, period: 20, nbdev: 1.0)
sma = SQA::TAI.sma(prices, period: 20)

# Track volatility compression
recent_vols = stddev.last(10).compact
avg_recent_vol = recent_vols.sum / recent_vols.size
longer_vols = stddev.last(50).compact
avg_longer_vol = longer_vols.sum / longer_vols.size

volatility_ratio = avg_recent_vol / avg_longer_vol
current_price = prices.last
current_high = highs.last
current_low = lows.last

puts "=== Volatility Breakout Setup ==="
puts "Volatility Ratio: #{(volatility_ratio * 100).round(1)}%"

if volatility_ratio < 0.5
  puts "Volatility compressed to 50% of normal"

  # Set breakout levels
  upper_breakout = sma.last + (stddev.last * 2.5)
  lower_breakout = sma.last - (stddev.last * 2.5)

  puts "\nBreakout Levels:"
  puts "Upper: $#{upper_breakout.round(2)}"
  puts "Lower: $#{lower_breakout.round(2)}"

  # Check for breakout
  if current_high > upper_breakout
    puts "\n*** BULLISH BREAKOUT ***"
    puts "Entry: $#{upper_breakout.round(2)}"
    puts "Target: $#{(upper_breakout + stddev.last * 4).round(2)}"
    puts "Stop: $#{(upper_breakout - stddev.last * 1.5).round(2)}"
  elsif current_low < lower_breakout
    puts "\n*** BEARISH BREAKOUT ***"
    puts "Entry: $#{lower_breakout.round(2)}"
    puts "Target: $#{(lower_breakout - stddev.last * 4).round(2)}"
    puts "Stop: $#{(lower_breakout + stddev.last * 1.5).round(2)}"
  else
    puts "\nWaiting for breakout direction..."
  end
end

Example: Volatility-Adjusted Stop Loss

prices = load_historical_prices('AMZN')

stddev = SQA::TAI.stddev(prices, period: 14, nbdev: 1.0)
atr = SQA::TAI.atr(highs, lows, prices, period: 14)

current_price = prices.last
current_stddev = stddev.last
current_atr = atr.last

puts "=== Volatility-Based Stop Placement ==="
puts "Current Price: $#{current_price.round(2)}"
puts "Standard Deviation: $#{current_stddev.round(2)}"
puts "ATR: $#{current_atr.round(2)}"

# Multiple stop loss approaches
stop_1sd = current_price - (current_stddev * 1.0)
stop_2sd = current_price - (current_stddev * 2.0)
stop_3sd = current_price - (current_stddev * 3.0)
stop_atr = current_price - (current_atr * 2.0)

puts <<~STOPS

  Stop Loss Options:
  1. Tight (1 SD):    $#{stop_1sd.round(2)} - Risk: $#{(current_price - stop_1sd).round(2)}
  2. Medium (2 SD):   $#{stop_2sd.round(2)} - Risk: $#{(current_price - stop_2sd).round(2)}
  3. Wide (3 SD):     $#{stop_3sd.round(2)} - Risk: $#{(current_price - stop_3sd).round(2)}
  4. ATR-based (2x):  $#{stop_atr.round(2)} - Risk: $#{(current_price - stop_atr).round(2)}

  Recommendation:
  - Day trades: Use 1-2 SD
  - Swing trades: Use 2-3 SD
  - Position trades: Use 3 SD or ATR
STOPS

Example: Volatility Expansion/Contraction Cycles

prices = load_historical_prices('SPY')

stddev = SQA::TAI.stddev(prices, period: 20, nbdev: 1.0)

# Calculate volatility trend
stddev_sma = SQA::TAI.sma(stddev.compact, period: 10)
current_vol = stddev.last
trend_vol = stddev_sma.last

# Identify cycle phase
volatility_trend = current_vol > trend_vol ? "Expanding" : "Contracting"
vol_change = ((current_vol - trend_vol) / trend_vol * 100).round(2)

# Historical context
vols_50 = stddev.last(50).compact
vols_200 = stddev.last(200).compact

avg_50 = vols_50.sum / vols_50.size
avg_200 = vols_200.sum / vols_200.size

puts <<~CYCLES
  === Volatility Cycle Analysis ===
  Current Volatility: #{current_vol.round(4)}
  Trend (10-period MA): #{trend_vol.round(4)}

  Cycle Phase: #{volatility_trend}
  Change from Trend: #{vol_change}%

  Historical Context:
  50-day Average: #{avg_50.round(4)}
  200-day Average: #{avg_200.round(4)}
CYCLES

if volatility_trend == "Expanding"
  puts "\nVolatility Expansion Phase:"
  puts "- Expect larger price swings"
  puts "- Widen stop losses"
  puts "- Reduce position sizes"
  puts "- Look for trend continuation"
else
  puts "\nVolatility Contraction Phase:"
  puts "- Range-bound market likely"
  puts "- Tighten stops"
  puts "- Prepare for breakout"
  puts "- Reduce directional bias"
end

Trading Strategies

1. Volatility Squeeze Breakout

  • Setup: STDDEV contracts to historical lows
  • Entry: Break of consolidation range
  • Target: Move equal to previous volatility expansion
  • Stop: Opposite side of consolidation range

2. Volatility Mean Reversion

  • Setup: STDDEV expands to extreme levels
  • Entry: Price returns toward moving average
  • Target: Return to normal volatility range
  • Stop: Beyond recent volatility extreme

3. Dynamic Stop Placement

  • Conservative: 3 × STDDEV from entry
  • Moderate: 2 × STDDEV from entry
  • Aggressive: 1 × STDDEV from entry
  • Adjust: As volatility changes

4. Position Sizing by Volatility

  • High Vol: Smaller positions (50-75% normal)
  • Normal Vol: Standard position size
  • Low Vol: Potentially larger (100-125% normal)
  • Formula: Risk / (2 × STDDEV) = Shares

Common Settings

Period Use Case Typical NBDEV
5-10 Short-term trading 1.0-1.5
14-20 Swing trading 1.0-2.0
20-30 Bollinger Bands 2.0
50-100 Position trading 2.0-3.0

Volatility Interpretation

STDDEV/Price Ratio Volatility Level Market State
< 1% Very Low Extreme compression
1-2% Low Range-bound
2-4% Normal Typical market
4-6% Elevated Active trending
> 6% High Extreme conditions

Advanced Techniques

1. Bollinger Band Construction

STDDEV is the foundation of Bollinger Bands: - Upper Band = SMA + (STDDEV × 2) - Middle Band = SMA - Lower Band = SMA - (STDDEV × 2)

2. Statistical Significance

  • 1 SD: 68% of prices within range
  • 2 SD: 95% of prices within range
  • 3 SD: 99.7% of prices within range

3. Volatility Clustering

Periods of high volatility tend to cluster together, as do periods of low volatility.

4. VIX Correlation

Compare equity STDDEV to VIX for broader market context.

See Also

  • Volatility Analysis Example
  • Risk Management Guide