Technical indicators are tools for pattern recognition, not crystal balls. They reflect past price behavior — they do not predict the future. Not financial advice.
Before OpenClaw can alert you to a signal, it needs to understand what that signal means. This module explains the five most important technical indicators — what they measure, why traders watch them, and how OpenClaw calculates them automatically.
A technical indicator is a calculation applied to a stock's price or volume history to help spot patterns. Think of it like a weather forecast — it doesn't tell you exactly what will happen, but it helps you make a more informed judgment.
Here's the key insight: indicators are mirrors of the past. They take historical price data and transform it into a number or signal that helps traders answer questions like:
These questions matter because traders use them to decide when to enter or exit positions — or when to simply wait on the sidelines.
OpenClaw calculates indicators automatically whenever a scan or alert runs. You don't write code. You don't pull up charts. Instead, you define your thresholds once in ta-config.yaml — the configuration file that tells OpenClaw what to watch for — and OpenClaw does the math for every ticker in your watchlist, every time it runs.
This is the whole point of OpenClaw: automation removes the manual work, so you never miss a signal.
OpenClaw focuses on five core indicators because they answer the most important questions about price movement. Here's a quick overview:
| Indicator | What It Measures | Good For |
|---|---|---|
| SMA — Simple Moving Average | Average price over N days | Spotting trend direction |
| EMA — Exponential Moving Average | Weighted average (recent days matter more) | Faster trend signals |
| RSI — Relative Strength Index | Overbought vs oversold on a 0–100 scale | Timing entries and exits |
| MACD — Moving Average Convergence/Divergence | Momentum — are two averages converging or diverging? | Spotting momentum shifts |
| Bollinger Bands | Volatility — how wide is the price range? | Identifying squeezes and breakouts |
Each of these answers a different question. Together, they give traders a 360-degree view of what the market is doing right now.
A Simple Moving Average (SMA) takes the last N closing prices and averages them. A 50-day SMA shows you the average price over the past 50 trading days — it smooths out the daily noise so you can see the underlying trend more clearly.
Imagine a stock bouncing all over the place day-to-day (that's normal). A moving average is like squinting at a noisy chart — the smaller details blur away, and you see the big picture.
An Exponential Moving Average (EMA) does the same thing but gives more weight to recent prices. If an SMA treats all 50 days equally, an EMA says "the last week matters more than a month ago." This makes EMA react faster to new price action.
Traders watch moving averages for two specific reasons:
1. Price vs Moving Average
When a stock's price is above its 50-day SMA, it's generally in an uptrend. When it's below — downtrend. This simple rule helps traders stay on the right side of the trend.
2. Golden Cross / Death Cross
When the 50-day SMA crosses above the 200-day SMA, it's called a "Golden Cross" — historically read as a bullish signal that the long-term trend is turning up. The opposite (50-day crossing below 200-day) is a "Death Cross" — a bearish signal.
OpenClaw calculates the 20, 50, and 200-day moving averages for every ticker in your watchlist every time a scan runs. If you have golden_cross: true in your config, it watches for that crossover event and sends an alert the day it happens. No manual chart checking required.
Here's what's happening under the hood when OpenClaw runs:
# OpenClaw calculates this automatically — here's what's happening under the hood
import yfinance as yf
import pandas_ta as ta
# Step 1: Download price history (OpenClaw does this from ta-config.yaml)
df = yf.download("AAPL", period="1y", interval="1d", progress=False)
df.columns = [c.lower() for c in df.columns]
# Step 2: Calculate moving averages
df["sma_20"] = ta.sma(df["close"], length=20)
df["sma_50"] = ta.sma(df["close"], length=50)
df["sma_200"] = ta.sma(df["close"], length=200)
df["ema_20"] = ta.ema(df["close"], length=20)
# Step 3: Read the latest values
latest = df.iloc[-1]
print(f"AAPL Close: ${latest['close']:.2f}")
print(f"SMA 20-day: ${latest['sma_20']:.2f}")
print(f"SMA 50-day: ${latest['sma_50']:.2f}")
print(f"SMA 200-day: ${latest['sma_200']:.2f}")
print()
# Step 4: Interpret the position
if latest["close"] > latest["sma_200"]:
print("✅ Price is ABOVE 200-day SMA — long-term uptrend")
else:
print("⚠️ Price is BELOW 200-day SMA — long-term downtrend")
# Step 5: Check for Golden Cross
prev = df.iloc[-2]
if latest["sma_50"] > latest["sma_200"] and prev["sma_50"] <= prev["sma_200"]:
print("🚨 GOLDEN CROSS detected today!")
Why This Matters: OpenClaw runs this exact code every time a scan happens. When it detects a Golden Cross, it fires an alert. You configured it once, and it handles everything else.
RSI measures how overbought or oversold a stock is, on a scale from 0 to 100. It compares recent gains to recent losses over a 14-day window.
Think of it like a pendulum. RSI tells you how far the pendulum has swung in one direction. When it swings too far in one direction, physics suggests it might swing back.
Here's the scale:
RSI below 30: The stock has been falling hard — some traders see this as an opportunity if the underlying fundamentals are fine. It's exhausted selling.
RSI above 70: The stock has been rallying hard — it may be due for a pause or pullback. It's exhausted buying.
Important caveat: RSI is most useful when combined with other signals. A stock can stay overbought for a long time in a strong bull market. RSI alone doesn't tell the whole story.
You set your RSI thresholds once in ta-config.yaml. OpenClaw checks every ticker in your watchlist and fires an alert the moment RSI crosses your threshold. You never have to manually check a chart again.
# RSI calculation — OpenClaw runs this for your entire watchlist
df["rsi"] = ta.rsi(df["close"], length=14)
latest_rsi = df["rsi"].iloc[-1]
print(f"AAPL RSI (14-day): {latest_rsi:.1f}")
# OpenClaw's threshold check — matches ta-config.yaml settings
RSI_OVERSOLD = 30 # from config: signals.rsi_oversold
RSI_OVERBOUGHT = 70 # from config: signals.rsi_overbought
if latest_rsi < RSI_OVERSOLD:
print(f"📉 RSI OVERSOLD — {latest_rsi:.1f} is below {RSI_OVERSOLD}")
print(" OpenClaw would fire an alert here")
elif latest_rsi > RSI_OVERBOUGHT:
print(f"📈 RSI OVERBOUGHT — {latest_rsi:.1f} is above {RSI_OVERBOUGHT}")
print(" OpenClaw would fire an alert here")
else:
print(f"😐 RSI neutral at {latest_rsi:.1f} — no alert triggered")
Customization: Don't like the 30/70 defaults? Change them in your config. OpenClaw will re-evaluate every scan with your new thresholds.
MACD tracks the difference between a 12-day EMA and a 26-day EMA. When those two averages are moving apart (diverging), momentum is building. When they're moving together (converging), momentum may be fading.
Think of it this way: if a fast car and slow car are getting further apart, the fast car is pulling away (momentum building). If they're getting closer together, the gap is closing (momentum fading).
MACD has three components:
A MACD Bullish Crossover happens when the MACD line crosses above the Signal line — often read as a momentum shift to the upside. A Bearish Crossover is the opposite.
These crossovers are objective signals. There's no guessing — when the lines cross, traders notice.
OpenClaw detects MACD crossovers automatically. If you have macd_cross: true in your config, it monitors the lines every scan and alerts you the moment a crossover happens.
# MACD — OpenClaw checks this on every scan
macd_result = ta.macd(df["close"], fast=12, slow=26, signal=9)
# pandas-ta returns a DataFrame with multiple columns
macd_col = [c for c in macd_result.columns if c.startswith("MACD_")][0]
signal_col = [c for c in macd_result.columns if c.startswith("MACDs_")][0]
hist_col = [c for c in macd_result.columns if c.startswith("MACDh_")][0]
df["macd"] = macd_result[macd_col]
df["macd_sig"] = macd_result[signal_col]
df["macd_hist"] = macd_result[hist_col]
cur = df.iloc[-1]
prev = df.iloc[-2]
print(f"MACD: {cur['macd']:.3f}")
print(f"Signal: {cur['macd_sig']:.3f}")
print(f"Histogram: {cur['macd_hist']:.3f}")
# Crossover detection
if cur["macd"] > cur["macd_sig"] and prev["macd"] <= prev["macd_sig"]:
print("🟢 MACD BULLISH CROSSOVER — momentum shifting up")
elif cur["macd"] < cur["macd_sig"] and prev["macd"] >= prev["macd_sig"]:
print("🔴 MACD BEARISH CROSSOVER — momentum shifting down")
else:
print("— No MACD crossover today")
Bollinger Bands draw two lines around a moving average — one above (upper band) and one below (lower band). The distance between the bands changes based on volatility: they widen when price swings are large, and they narrow when price is calm.
Think of the bands as the "normal range" for a stock. When price breaks outside that range, something unusual is happening.
1. Price Near the Bands: When price touches the upper band, it's stretched to the high side. Near the lower band, it's stretched to the low side. This tells you whether a stock is extreme or not.
2. The Squeeze: When the bands get very narrow (low volatility), it often precedes a sharp move in either direction. OpenClaw can detect this compression before the breakout happens — giving you early warning.
OpenClaw tracks the band "bandwidth" (the distance between upper and lower). When bandwidth drops to historically low levels, it fires a squeeze alert. This is often a warning that a big move is coming.
# Bollinger Bands — OpenClaw uses this for squeeze detection
bb = ta.bbands(df["close"], length=20, std=2)
upper_col = [c for c in bb.columns if "BBU" in c][0]
lower_col = [c for c in bb.columns if "BBL" in c][0]
bw_col = [c for c in bb.columns if "BBB" in c][0] # bandwidth
df["bb_upper"] = bb[upper_col]
df["bb_lower"] = bb[lower_col]
df["bb_bw"] = bb[bw_col]
cur = df.iloc[-1]
bw_20th_pct = df["bb_bw"].quantile(0.20) # historical low-volatility threshold
print(f"Upper Band: ${cur['bb_upper']:.2f}")
print(f"Price: ${cur['close']:.2f}")
print(f"Lower Band: ${cur['bb_lower']:.2f}")
print(f"Bandwidth: {cur['bb_bw']:.3f} (20th pct: {bw_20th_pct:.3f})")
if cur["bb_bw"] < bw_20th_pct:
print("⚡ SQUEEZE DETECTED — volatility at historic low, breakout watch")
The real power of OpenClaw isn't in any single indicator — it's in automation. You configure all your indicator settings in one place: ta-config.yaml. OpenClaw reads this file every time a scan runs and checks all your thresholds for all your tickers.
# ta-config.yaml — configure ALL your indicator settings in one place
# OpenClaw reads this file every time a scan or alert runs
watchlist:
tickers:
- AAPL
- MSFT
- NVDA
- SPY
- QQQ
signals:
# Moving averages — set to true to enable each signal type
golden_cross: true # Alert when SMA50 crosses above SMA200
death_cross: true # Alert when SMA50 crosses below SMA200
# RSI thresholds — adjust to your trading style
rsi_oversold: 30 # Alert when RSI drops below this
rsi_overbought: 70 # Alert when RSI rises above this
# MACD crossover alerts
macd_cross: true # Alert on bullish or bearish MACD crossover
# Bollinger Band squeeze
bb_squeeze: true # Alert when bandwidth drops to historic low
scanner:
lookback_period: "1y" # How much history to fetch
export_csv: true # Save results to CSV after each scan
alerts:
email: "you@example.com"
cooldown_hours: 24 # Wait this long before re-alerting the same signal
daily_digest: true # Send one summary email instead of individual alerts
Once ta-config.yaml is set up, you don't touch the code. To add a ticker, add a line under tickers:. To adjust RSI sensitivity, change the threshold number. To enable or disable a signal type, flip it to true or false.
OpenClaw handles everything else.
Every scan, OpenClaw:
This is the entire idea: configuration, not code.
| Indicator | Value / Signal | What OpenClaw Flags |
|---|---|---|
| RSI | Below 30 | Oversold — potential bounce watch |
| RSI | Above 70 | Overbought — potential pullback watch |
| SMA 50 vs 200 | 50 crosses above 200 | Golden Cross — trend turning bullish |
| SMA 50 vs 200 | 50 crosses below 200 | Death Cross — trend turning bearish |
| MACD | Line crosses above Signal | Bullish momentum shift |
| MACD | Line crosses below Signal | Bearish momentum shift |
| Bollinger Bandwidth | At 20th percentile low | Squeeze — breakout likely coming |
OpenClaw needs three packages to calculate indicators. If you haven't installed them yet, run this once:
# Install the three packages OpenClaw's TA module needs
pip install yfinance pandas-ta pandas
# Test your setup
python3 -c "import yfinance, pandas_ta; print('✅ OpenClaw TA ready')"
If you see ✅ OpenClaw TA ready, you're good to go.