HeyTraders Documentation

Mean Reversion Strategies

Bollinger Band Mean Reversion

Tags: mean_reversion, bbands, oversold, bounce Functions: bollinger_bands Description: Buys when price touches the lower Bollinger Band and bounces up, exits at the middle band. Code:

ticker = context['ticker']
upper, middle, lower = bollinger_bands(close, 20, 2)

# Touch lower band and bounce
touch_lower = close <= lower
bounce = close > close.shift(1)
long_cond = (touch_lower) & (bounce)

# Exit at middle or upper band
exit_cond = close >= middle

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

Bollinger Band Squeeze Breakout

Tags: volatility, bbands, squeeze, breakout Functions: bollinger_bands, std Description: Buys when price breaks above the upper Bollinger Band after the band width has contracted, capturing volatility expansion. Code:

ticker = context['ticker']
upper, middle, lower = bollinger_bands(close, 20, 2)

# Band width
band_width = (upper - lower) / middle
bw_avg = ts_mean(band_width, 50)

# Squeeze: current width < 0.7x average
squeeze = band_width < bw_avg * 0.7
# Breakout above upper band
breakout = close > upper

long_cond = (squeeze.shift(1)) & (breakout)
exit_cond = close < middle

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

Z-Score Mean Reversion

Tags: mean_reversion, zscore, statistical Functions: ts_zscore Description: Buys when the price Z-score falls below -2 (extreme undervaluation) and exits when it returns to 0. Code:

ticker = context['ticker']
z_score = ts_zscore(close, 20)

long_cond = z_score < -2
exit_cond = z_score > 0

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

RSI Mean Reversion with Confirmation

Tags: mean_reversion, rsi, confirmation, turning_point Functions: rsi Description: Enters when RSI is below 30 and already turning upward, improving win rate over a simple threshold cross. Code:

ticker = context['ticker']
rsi_val = rsi(close, 14)

# Oversold AND turning up
oversold = rsi_val < 30
turning_up = rsi_val > rsi_val.shift(1)
long_cond = (oversold) & (turning_up)

# Exit when RSI normalizes
exit_cond = rsi_val > 50

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

Double Bottom RSI

Tags: mean_reversion, rsi, pattern, double_bottom Functions: rsi, ts_mean Description: Buys when RSI is below 30 and the second RSI trough is higher than the first (bullish RSI divergence). Code:

ticker = context['ticker']
rsi_val = rsi(close, 14)

# Current RSI oversold
oversold = rsi_val < 30
# RSI making higher low (vs 5 bars ago)
higher_low = (rsi_val > rsi_val.shift(5)) & (close < close.shift(5))

long_cond = (oversold) & (higher_low)
exit_cond = rsi_val > 60

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

Keltner Channel Reversion

Tags: mean_reversion, keltner, atr, channel Functions: ema, atr Description: Buys when price re-enters the Keltner Channel after breaking below the lower band. Code:

ticker = context['ticker']
ema20 = ema(close, 20)
atr_val = atr(high, low, close, 14)

kc_upper = ema20 + atr_val * 2
kc_lower = ema20 - atr_val * 2

# Price was below lower band, now re-entering
was_below = close.shift(1) < kc_lower
re_enter = close > kc_lower

long_cond = (was_below) & (re_enter)
exit_cond = close > ema20

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

Oversold Stochastic Mean Reversion

Tags: mean_reversion, stochastic, oversold Functions: stoch Description: Buys when Stochastic crosses above 20 after reaching an extreme oversold level below 10. Code:

ticker = context['ticker']
slowk, slowd = stoch(high, low, close, 14, 3, 3)

# Was extremely oversold, now recovering
was_extreme = slowk.shift(1) < 10
recovering = slowk > 20

long_cond = (was_extreme) & (recovering)
exit_cond = slowk > 70

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

Price-MA Distance Reversion

Tags: mean_reversion, ma, distance, deviation Functions: sma Description: Buys when price drops more than 5% below the 20-day MA, expecting a reversion back to the mean. Code:

ticker = context['ticker']
ma20 = sma(close, 20)

# Distance from MA
distance_pct = (close - ma20) / ma20

# More than 5% below MA
oversold = distance_pct < -0.05
# Showing signs of recovery
recovering = close > close.shift(1)

long_cond = (oversold) & (recovering)
exit_cond = close > ma20

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))

Perpetual Mean Reversion Long/Short

Tags: mean_reversion, zscore, perpetual, long_short Functions: ts_zscore Description: Bidirectional Z-score mean reversion on futures: long when Z < -2 and short when Z > 2. Code:

ticker = context['ticker']
z_score = ts_zscore(close, 20)

long_cond = z_score < -2
short_cond = z_score > 2
exit_long = z_score > 0
exit_short = z_score < 0

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(short_cond, entry(ticker, 'SHORT', Weight(1.0)))
emit(exit_long, exit_position(ticker))
emit(exit_short, exit_position(ticker))

Williams %R Extreme Reversion

Tags: mean_reversion, williams_r, extreme, oversold Functions: williams_r Description: Buys when Williams %R rebounds from an extreme oversold level below -90. Code:

ticker = context['ticker']
wr = williams_r(high, low, close, 14)

# Extreme oversold (-90 or below) and bouncing
extreme_oversold = wr < -90
bouncing = wr > wr.shift(1)

long_cond = (extreme_oversold) & (bouncing)
exit_cond = wr > -20

emit(long_cond, entry(ticker, 'LONG', Weight(1.0)))
emit(exit_cond, exit_position(ticker))