Skip to main content

Indicators & Signals

Indicators are mathematical calculations based on price, volume, or other market data. They form the building blocks of trading signals.

What is a Signal?

A signal is a trigger that suggests a trading action. Signals are typically generated from indicators.

Indicator → Condition → Signal → Action
↓ ↓ ↓ ↓
RSI RSI < 30 Buy Open long

Trend Indicators

Moving Averages

Smooth price data to identify trends.

Simple Moving Average (SMA)

def sma(prices, window):
return sum(prices[-window:]) / window

# Usage
sma_20 = sma(close_prices, 20)
sma_50 = sma(close_prices, 50)

# Signal: Golden Cross (SMA20 crosses above SMA50)
if sma_20 > sma_50 and prev_sma_20 <= prev_sma_50:
signal = "BUY"

Exponential Moving Average (EMA)

Gives more weight to recent prices.

def ema(prices, window):
multiplier = 2 / (window + 1)
ema = prices[0]
for price in prices[1:]:
ema = (price - ema) * multiplier + ema
return ema

# VecAlpha built-in
ema_20 = self.ema(20) # In strategy class

Average Directional Index (ADX)

Measures trend strength (not direction).

ADX ValueTrend Strength
0-25Weak or no trend
25-50Strong trend
50-75Very strong trend
75-100Extremely strong
adx = self.adx(14)
if adx > 25:
# Strong trend - use trend-following strategies
else:
# Weak trend - consider mean-reversion

Momentum Indicators

Relative Strength Index (RSI)

Measures speed and magnitude of price changes.

RSI = 100 - (100 / (1 + RS))
RS = Average Gain / Average Loss
RSI RangeInterpretation
> 70Overbought
50-70Bullish
30-50Bearish
< 30Oversold
rsi = self.rsi(14)

# Mean reversion signals
if rsi < 30:
signal = "BUY" # Oversold
elif rsi > 70:
signal = "SELL" # Overbought

MACD (Moving Average Convergence Divergence)

Combines trend and momentum.

macd, signal_line, histogram = self.macd(12, 26, 9)

# Crossover signal
if macd > signal_line and prev_macd <= prev_signal:
signal = "BUY"
elif macd < signal_line and prev_macd >= prev_signal:
signal = "SELL"

Volatility Indicators

Bollinger Bands

Volatility-based envelopes around price.

Middle Band = 20 SMA
Upper Band = Middle + (2 × Standard Deviation)
Lower Band = Middle - (2 × Standard Deviation)
upper, middle, lower = self.bollinger(20, 2)

# Mean reversion signal
if price < lower:
signal = "BUY" # Price at lower band
elif price > upper:
signal = "SELL" # Price at upper band

Average True Range (ATR)

Measures volatility.

atr = self.atr(14)

# Use for position sizing
stop_loss_distance = 2 * atr
position_size = risk_amount / stop_loss_distance

Volume Indicators

On-Balance Volume (OBV)

Tracks cumulative volume flow.

obv = self.obv()

# Divergence detection
if price_making_new_highs and obv_not_making_new_highs:
signal = "POTENTIAL_REVERSAL"

Volume Weighted Average Price (VWAP)

Average price weighted by volume.

vwap = self.vwap()

# Mean reversion
if price < vwap:
# Price below VWAP - potential buy
signal = "BUY"

Combining Indicators

Single indicators are rarely enough. Combine multiple for confirmation:

Example: Trend + Momentum

def generate_signal(self):
# Trend filter
trend = self.sma(50) > self.sma(200)

# Momentum signal
rsi = self.rsi(14)

# Combined signal
if trend and rsi < 40: # Uptrend + oversold
return "BUY"
elif not trend and rsi > 60: # Downtrend + overbought
return "SELL"

return "HOLD"

Example: Multiple Timeframes

def multi_timeframe_signal(self):
# Higher timeframe trend
daily_trend = self.sma(50, timeframe='1d') > self.sma(200, timeframe='1d')

# Lower timeframe entry
hourly_rsi = self.rsi(14, timeframe='1h')

if daily_trend and hourly_rsi < 30:
return "BUY"
return "HOLD"

Indicator Best Practices

1. Understand What You're Measuring

CategoryWhat It MeasuresExample Indicators
TrendDirection of price movementSMA, EMA, ADX
MomentumSpeed of price changeRSI, MACD, Stochastic
VolatilityMagnitude of price swingsATR, Bollinger Bands
VolumeTrading activityOBV, VWAP, Volume

2. Avoid Redundancy

Don't use multiple indicators that measure the same thing:

# REDUNDANT: All measure momentum
indicators = ['RSI', 'Stochastic', 'CCI']

# BETTER: Different aspects
indicators = ['RSI', 'MACD', 'ATR'] # Momentum + Trend + Volatility

3. Match Indicators to Strategy Type

Strategy TypeBest Indicators
Trend FollowingSMA, EMA, ADX, MACD
Mean ReversionRSI, Bollinger Bands, Stochastic
BreakoutATR, Donchian Channels
Pairs TradingCointegration, Correlation

4. Parameter Selection

Common parameter ranges:

IndicatorDefaultRange to Test
SMA/EMA20, 50, 20010-200
RSI147-21
MACD12, 26, 9Various
Bollinger20, 215-25, 1.5-2.5

Custom Indicators

Create your own in VecAlpha:

from vecalpha import Indicator

class CustomIndicator(Indicator):
"""Custom momentum indicator."""

def __init__(self, window=14):
self.window = window

def calculate(self, data):
closes = data['close']
volumes = data['volume']

# Custom calculation
momentum = closes.pct_change(self.window)
volume_weight = volumes / volumes.rolling(self.window).mean()

return momentum * volume_weight

# Use in strategy
custom = CustomIndicator(14)
signal_value = custom.calculate(self.data)

Next Steps