The Quest Begins (The “Why”)
I still remember the first time I stared at a candlestick chart and felt like I was trying to read ancient runes. My buddy kept shouting “Buy the dip!” while I was over here wondering if the dip was just a typo. I spent hours copying formulas from textbooks into a notebook, only to end up with a spreadsheet that looked more like a modern art piece than a trading signal. The frustration was real: I knew there was a rhythm to price action, but I couldn’t hear it.
That’s when I realized I needed two trusty side‑kicks: a moving average to smooth out the noise and the Relative Strength Index (RSI) to tell me when the market was getting over‑excited or too shy. Think of them as the scout and the lookout on a treasure hunt—one tells you the general direction, the other warns you when you’re getting close to a trap.
The Revelation (The Insight)
Moving averages are basically a way to ask, “What’s the average price over the last n periods?” The simple moving average (SMA) treats every period equally, while the exponential moving average (EMA) gives more weight to recent prices—so it reacts faster when the market decides to sprint.
The RSI, on the other hand, measures the speed and size of price changes. It oscillates between 0 and 100. Traditionally, readings above 70 hint at overbought conditions (maybe a pullback is coming), and readings below 30 hint at oversold conditions (maybe a bounce is due). The magic happens when you combine them: a price crossing above its 50‑day SMA and an RSI climbing out of the oversold zone can be a solid “go” signal, while the opposite combo often warns you to step back.
It felt like when Harry Potter casts Expecto Patronum to light up a dark corridor—suddenly the path ahead becomes visible, and you know which shadows to avoid.
Wielding the Power (Code & Examples)
Let’s turn that insight into something you can actually run. I’ll start with the “struggle” version—manual loops that are slow and error‑prone—then show the “victory” version using pandas, which is both concise and lightning‑fast.
The Struggle: Manual SMA & RSI
# NOTE: This is deliberately verbose to show the pain.
def manual_sma(prices, window):
sma = []
for i in range(len(prices)):
if i < window - 1:
sma.append(None) # not enough data yet
else:
window_prices = prices[i-window+1:i+1]
sma.append(sum(window_prices) / window)
return sma
def manual_rsi(prices, window=14):
# compute price changes
deltas = [prices[i] - prices[i-1] for i in range(1, len(prices))]
up = [max(d, 0) for d in deltas]
down = [-min(d, 0) for d in deltas]
# first average gain/loss
avg_gain = sum(up[:window]) / window
avg_loss = sum(down[:window]) / window
rsi = [None] * window # first `window` values undefined
for i in range(window, len(deltas)):
avg_gain = (avg_gain * (window-1) + up[i]) / window
avg_loss = (avg_loss * (window-1) + down[i]) / window
if avg_loss == 0:
rsi.append(100)
else:
rs = avg_gain / avg_loss
rsi.append(100 - (100 / (1 + rs)))
return rsi
Running this on a dataframe with thousands of rows feels like watching a snail race a cheetah. Plus, it’s easy to slip up—like forgetting to shift the deltas array, which throws off the whole RSI calculation.
The Victory: Pandas‑Powered SMA & RSI
import pandas as pd
import numpy as np
def add_indicators(df, price_col='close', sma_window=50, ema_window=20, rsi_window=14):
# ----- Moving Averages -----
df['SMA'] = df[price_col].rolling(window=sma_window).mean()
df['EMA'] = df[price_col].ewm(span=ema_window, adjust=False).mean()
# ----- RSI -----
delta = df[price_col].diff()
up = delta.clip(lower=0)
down = -delta.clip(upper=0)
# Exponential moving average of gains/losses (the common way)
roll_up = up.ewm(span=rsi_window, adjust=False).mean()
roll_down = down.ewm(span=rsi_window, adjust=False).mean()
rs = roll_up / roll_down
df['RSI'] = 100 - (100 / (1 + rs))
return df
# Example usage:
# df = pd.read_csv('AAPL_daily.csv')
# df = add_indicators(df)
# print(df.tail())
Why this feels like a win:
- One line for the SMA (
rolling.mean()), one line for the EMA (ewm().mean()). - The RSI calculation uses pandas’ built‑in
clipandewm, removing the need to manage loops or worry about off‑by‑one errors. - The result is a dataframe ready for plotting or feeding into a back‑tester—in seconds, not minutes.
Common Traps to Avoid
- Using the wrong window for RSI – The classic 14‑period works for many timeframes, but if you’re on a 5‑minute chart you might want a shorter window (e.g., 7) to stay responsive. Blindly applying 14 everywhere can give you stale signals.
- Treating RSI >70 as an automatic sell signal – In a strong uptrend, the RSI can stay overbought for weeks. Always check the price’s relation to its moving average; if price is above a rising SMA, an overbought RSI may just mean momentum, not exhaustion.
Why This New Power Matters
With these indicators in your toolbox, you can go from “guessing” to “having a rule‑based framework.” Imagine building a simple scanner that flags stocks when:
- Price crosses above its 50‑day SMA and
- RSI rises from below 30 to above 30 (exiting oversold)
That’s a classic “pull‑back‑in‑an‑uptrend” setup, and you can implement it in under ten lines of pandas. Suddenly you’re not just watching charts; you’re generating actionable ideas, back‑testing them, and iterating like a true quant.
The best part? The concepts scale. Swap the SMA for an EMA to catch faster moves, or add a second RSI divergence check to spot weakening momentum. Each tweak feels like unlocking a new spell in your grimoire—except the mana is just clean, readable Python code.
Your Turn: The Next Quest
Grab a dataset (yahoo‑finance, Alpha Vantage, or even a CSV you already have), slap the add_indicators function on it, and experiment. Try tweaking the windows, plot the SMA/EMA together with price, and see how the RSI behaves during a breakout versus a fakeout.
What’s the first signal you’ll hunt for? Share your findings in the comments—let’s keep the adventure going!
Happy coding, and may your trends be ever in your favor.
Top comments (0)