Envelopes (Moving Average Envelopes)
I. What is the Envelopes Indicator
Envelopes, also known as Moving Average Envelopes, is a classic technical analysis indicator. It creates a price “envelope” channel by placing a parallel line at a fixed percentage offset above and below a moving average.
Envelopes belongs to the Volatility / Bands overlay indicator category and has no single attributed inventor — it is one of the earliest and most fundamental channel indicators in technical analysis, dating back to mid-20th century technical analysis practices.
Envelopes consists of three lines:
- Middle Line: Simple Moving Average (SMA) of the closing price
- Upper Envelope: Middle Line x (1 + Percentage)
- Lower Envelope: Middle Line x (1 - Percentage)
The default parameters are period , percentage offset , and the data source is the closing price.
The key difference between Envelopes and Bollinger Bands is: Envelopes uses a fixed percentage offset with a constant bandwidth, while Bollinger Bands uses a standard deviation offset with bandwidth that adapts to volatility. This means Envelopes is simpler but less adaptive than Bollinger Bands in markets with dramatic volatility changes.
II. Mathematical Principles and Calculation
2.1 Core Formulas
Let the closing price series be , the period be , and the percentage offset be (in decimal form, e.g., 2.5% -> 0.025).
Middle Line:
Upper Envelope:
Lower Envelope:
2.2 Formula Variants
Some implementations use addition/subtraction instead of multiplication/division:
The two notations are mathematically equivalent.
Additionally, the middle line can use EMA instead of SMA:
The EMA version is more sensitive to price changes.
2.3 Channel Width
The channel width of Envelopes is proportional to the middle line:
The relative width is always constant:
This means the relative channel width of Envelopes never changes (e.g., with , the width is always 5% of the middle line), and it cannot reflect changes in volatility.
2.4 Calculation Steps
- Calculate the SMA of closing prices (period ) -> middle line
- Upper Envelope = Middle Line x
- Lower Envelope = Middle Line x
The calculation is extremely straightforward — essentially just shifting the moving average up and down by a percentage. This simplicity is both the strength of Envelopes (easy to understand and implement) and its limitation (does not account for volatility changes).
III. Python Implementation
import numpy as np
import pandas as pd
def envelopes(close: pd.Series, period: int = 20, percent: float = 2.5,
ma_type: str = 'sma') -> pd.DataFrame:
"""
Calculate Moving Average Envelopes.
Parameters:
close : closing price series
period : moving average period, default 20
percent : percentage offset, default 2.5 (i.e., 2.5%)
ma_type : moving average type, 'sma' or 'ema'
Returns:
DataFrame with columns: middle, upper, lower
"""
p = percent / 100.0
# Calculate the middle line
if ma_type == 'ema':
middle = close.ewm(span=period, adjust=False).mean()
else:
middle = close.rolling(window=period).mean()
# Upper and lower envelopes
upper = middle * (1 + p)
lower = middle * (1 - p)
return pd.DataFrame({
'middle': middle,
'upper': upper,
'lower': lower
})
def envelope_signals(close: pd.Series, upper: pd.Series,
lower: pd.Series, middle: pd.Series) -> pd.Series:
"""
Generate trading signals based on Envelopes.
Signal logic:
- Price breaks below the lower envelope -> Oversold (potential buy)
- Price breaks above the upper envelope -> Overbought (potential sell)
- Price crosses the middle line -> Trend confirmation
"""
signals = pd.Series('Neutral', index=close.index)
# Oversold / Overbought signals
signals[close < lower] = 'Oversold'
signals[close > upper] = 'Overbought'
# Middle line crossover signals (when not overbought/oversold)
cross_up = (close > middle) & (close.shift(1) <= middle.shift(1))
cross_down = (close < middle) & (close.shift(1) >= middle.shift(1))
signals[cross_up & (signals == 'Neutral')] = 'Cross Above Middle'
signals[cross_down & (signals == 'Neutral')] = 'Cross Below Middle'
return signals
# ============ Usage Example ============
if __name__ == '__main__':
np.random.seed(42)
n_days = 100
# Generate simulated OHLCV data
base_price = 100 + np.cumsum(np.random.randn(n_days) * 0.5)
df = pd.DataFrame({
'open': base_price + np.random.randn(n_days) * 0.3,
'high': base_price + np.abs(np.random.randn(n_days) * 0.8),
'low': base_price - np.abs(np.random.randn(n_days) * 0.8),
'close': base_price,
'volume': np.random.randint(1000, 10000, n_days)
})
# Calculate Envelopes (SMA version)
env_sma = envelopes(df['close'], period=20, percent=2.5, ma_type='sma')
result = pd.concat([df[['close']], env_sma], axis=1)
print("=== Envelopes (SMA, 2.5%) Results (last 10 rows) ===")
print(result.tail(10).to_string())
# Calculate Envelopes (EMA version)
env_ema = envelopes(df['close'], period=20, percent=2.5, ma_type='ema')
print("\n=== Envelopes (EMA, 2.5%) Results (last 5 rows) ===")
cols = env_ema.add_suffix('_ema')
print(pd.concat([df[['close']], cols], axis=1).tail(5).to_string())
# Generate trading signals
signals = envelope_signals(df['close'], env_sma['upper'],
env_sma['lower'], env_sma['middle'])
print("\n=== Signal Statistics ===")
print(signals.value_counts())
# Display selected signals
signal_rows = df[['close']].copy()
signal_rows['upper'] = env_sma['upper']
signal_rows['lower'] = env_sma['lower']
signal_rows['signal'] = signals
non_neutral = signal_rows[signal_rows['signal'] != 'Neutral']
print(f"\n=== Non-Neutral Signals (total: {len(non_neutral)}) ===")
print(non_neutral.head(10).to_string())
IV. Problems the Indicator Solves
4.1 Overbought / Oversold Identification
The most basic use of Envelopes is identifying overbought and oversold price conditions:
- Price breaks above the upper envelope: Price has deviated too far from the moving average — possibly overbought
- Price breaks below the lower envelope: Price has deviated too far from the moving average — possibly oversold
This logic is based on the mean reversion principle — price cannot deviate from the moving average indefinitely and will eventually revert.
4.2 Mean Reversion Trading
In range-bound markets, Envelopes provides clear trading rules:
- Price touches the lower envelope -> Buy
- Price returns to the middle line -> Take profit (or hold until the upper envelope)
- Price touches the upper envelope -> Sell
- Price returns to the middle line -> Take profit
4.3 Trend Filtering
- Price consistently above the middle line -> Bullish trend
- Price consistently below the middle line -> Bearish trend
- Middle line direction (rising or falling) reflects trend direction
Envelopes uses a fixed percentage, which means that during high-volatility periods, price may frequently break through the channel producing many false signals; during low-volatility periods, price may never reach the channel boundaries, missing trading opportunities. Therefore, the percentage parameter must be adjusted according to the volatility characteristics of the asset.
4.4 Combining with Other Indicators
- Combine with RSI to confirm overbought/oversold: When price touches the upper band and RSI > 70, the overbought signal is more reliable
- Combine with volume for confirmation: Breakouts accompanied by increased volume are more valid
- Combine with trend indicators for filtering: Only go long in uptrends and short in downtrends
V. Advantages, Disadvantages, and Use Cases
Advantages
| Advantage | Description |
|---|---|
| Extremely simple | Only requires a moving average and a fixed percentage — minimal computation |
| Few parameters | Only two parameters: period and percentage |
| Intuitive | The channel meaning is immediately clear |
| Good for stable markets | Performs well with assets that have relatively stable volatility |
Disadvantages
| Disadvantage | Description |
|---|---|
| Not adaptive to volatility | Fixed percentage cannot adjust with changing market volatility |
| Subjective parameter choice | The percentage must be manually adjusted based on the asset and timeframe |
| Fails in high volatility | In strong trends or high volatility, price may run outside the channel for extended periods |
| Superseded by Bollinger Bands | Bollinger Bands is an improvement over Envelopes in nearly every respect |
Use Cases
- Best suited for: Assets with stable volatility (e.g., some large-cap blue chips, stable forex pairs)
- Moderately suited for: Mean reversion trading in range-bound markets
- Not suited for: High-volatility assets (e.g., small-cap stocks, cryptocurrencies); trending markets
Percentage Parameter Reference
| Timeframe | Suggested Percentage | Notes |
|---|---|---|
| Daily | 1%—3% | Depends on asset volatility |
| Weekly | 3%—5% | Larger timeframes need larger percentages |
| Minute | 0.1%—0.5% | Shorter timeframes need smaller percentages |
Rule of thumb for choosing the percentage: Backtest historical data and select a percentage that keeps the price inside the channel approximately 90%—95% of the time. If breakouts are too frequent, the percentage is too small; if breakouts almost never occur, the percentage is too large. You can also calculate the asset’s historical volatility as a reference for setting the percentage.
Comparison with Similar Indicators
| Indicator | Channel Width | Adaptiveness | Complexity |
|---|---|---|---|
| Envelopes | Fixed percentage | None | Lowest |
| Bollinger Bands | Standard deviation | Adapts to volatility | Medium |
| Keltner Channels | ATR | Adapts to volatility | Higher |
Overall, Envelopes is a good starting point for learning channel indicators, but in actual trading, adaptive indicators such as Bollinger Bands or Keltner Channels are generally recommended as alternatives.