Finding the One: Moving Averages and RSI Indicators – A Neo’s Guide

The Quest Begins (The “Why”)

Honestly, I was staring at a candlestick chart at 2 a.m., coffee gone cold, wondering why my “gut feeling” trades kept landing me in the red. I’d read a dozen blog posts that shouted “use moving averages!” and “RSI is your friend!” but every time I tried to slap them together in a script, I ended up with a tangled mess of loops, off‑by‑one errors, and signals that looked like random noise. It felt like I was trying to dodge bullets in The Matrix without ever seeing the code behind them.

I needed a solid foundation — something I could trust, back‑test, and actually build a strategy around. So I embarked on a quest to demystify two of the most talked‑about indicators: the Simple Moving Average (SMA) and the Relative Strength Index (RSI). If you’ve ever felt stuck in a loop of second‑guessing every tick, you know exactly where I’m coming from.

The Revelation (The Insight)

The “aha!” moment came when I stopped treating the indicators as magical black boxes and started looking at the math behind them.

  • SMA is just the average price over a look‑back window. It smooths out the noise so you can see the underlying trend.
  • RSI measures the speed and magnitude of price changes on a scale from 0 to 100. Values above 70 hint at overbought conditions; below 30 hint at oversold.

The real power isn’t in the numbers themselves — it’s in how they interact. When a short‑term SMA crosses above a long‑term SMA, many traders interpret that as a bullish shift (the classic “golden cross”). Pair that with an RSI pulling back from overbought territory, and you have a higher‑probability entry signal.

Seeing the formulas laid out made the indicators feel less like fortune‑telling and more like a set of tools I could wield with confidence.

Wielding the Power (Code & Examples)

The Struggle: Naïve Loops

My first attempt was a classic “for‑loop over every bar” disaster. It worked, but it was slow, error‑prone, and a pain to read. Here’s a taste of what that looked like (Python‑ish pseudocode):

# 🚫 DON’T DO THIS – SLOW & BUGGY
def sma_manual(prices, window):
    result = [None] * len(prices)
    for i in range(len(prices)):
        if i + 1 >= window:
            result[i] = sum(prices[i-window+1:i+1]) / window
    return result

def rsi_manual(prices, period=14):
    gains = [0] * len(prices)
    losses = [0] * len(prices)
    for i in range(1, len(prices)):
        change = prices[i] - prices[i-1]
        if change > 0:
            gains[i] = change
        else:
            losses[i] = -change
    # first average gain/loss
    avg_gain = sum(gains[:period]) / period
    avg_loss = sum(losses[:period]) / period
    rsi = [None] * len(prices)
    for i in range(period, len(prices)):
        avg_gain = (avg_gain * (period-1) + gains[i]) / period
        avg_loss = (avg_loss * (period-1) + losses[i]) / period
        if avg_loss == 0:
            rsi[i] = 100
        else:
            rs = avg_gain / avg_loss
            rsi[i] = 100 - (100 / (1 + rs))
    return rsi

Problems:

  • Look‑ahead bias – I accidentally used future data when I wasn’t careful with indices.
  • Repeated sums – O(n·window) complexity made it crawl on anything beyond a few hundred rows.
  • Magic numbers – Hard‑coded periods scattered everywhere.

The Victory: Vectorized Pandas Magic

Switching to pandas’ built‑in rolling operations felt like Neo finally seeing the Matrix code — everything snapped into place.

import pandas as pd
import numpy as np

# Assume df is a DataFrame with a 'close' column indexed by time
df = pd.read_csv('ohlc_data.csv', parse_dates=['timestamp'])
df.set_index('timestamp', inplace=True)

# ---------- Simple Moving Averages ----------
# 20‑day short SMA, 50‑day long SMA
df['SMA_20'] = df['close'].rolling(window=20).mean()
df['SMA_50'] = df['close'].rolling(window=50).mean()

# ---------- Relative Strength Index ----------
delta = df['close'].diff()
gain = delta.clip(lower=0)
loss = -delta.clip(upper=0)

# Exponential moving average of gains/losses (the classic Wilder's smoothing)
avg_gain = gain.ewm(alpha=1/14, adjust=False).mean()
avg_loss = loss.ewm(alpha=1/14, adjust=False).mean()

rs = avg_gain / avg_loss
df['RSI'] = 100 - (100 / (1 + rs))

# ---------- Signal Generation ----------
# Bullish when short SMA crosses above long SMA AND RSI < 70 (not overbought)
df['signal'] = np.where(
    (df['SMA_20'] > df['SMA_50']) & (df['SMA_20'].shift(1) <= df['SMA_50'].shift(1)) &
    (df['RSI'] < 70),
    1,  # go long
    0   # stay flat
)

Why this feels like a win:

  • Speed – rolling and ewm are implemented in C; they blaze through millions of rows.
  • Safety – the .shift(1) ensures we’re only using past data, eliminating look‑ahead bias.
  • Readability – each step is a single, expressive line.

Traps to Avoid (The “Bosses” on Our Quest)

  1. Using .mean() on the raw series without handling NaNs – the first window‑1 rows will be NaN; if you forget to drop or fill them, later comparisons can misfire.
  2. Confusing SMA with EMA – they react differently to price spikes. If you need a more responsive average, swap rolling().mean() for ewm(span=20).mean().
  3. RSI boundaries – Remember that RSI can stay extreme ( >70 or <30 ) during strong trends. Treating every >70 as a sell signal will get you whipsawed in a bull run.

Why This New Power Matters

Now that I can compute SMA and RSI reliably, I’ve built a tiny back‑testing framework that lets me test ideas in minutes instead of hours. I’ve experimented with:

  • SMA crossovers filtered by RSI to reduce false entries.
  • RSI divergence spotting when price makes a new high but RSI fails to follow — classic reversal clues.
  • Combining with volume – adding a volume‑weighted moving average to confirm strength.

The best part? The same code works for crypto, forex, or equities — just swap the CSV. It’s like having a universal spell book that adapts to any market.

If you’re curious, try adding an EMA‑based MACD on top of this foundation. You’ll see how these indicators stack together to create richer, more robust strategies.

Your Turn – The Challenge

Here’s a quest for you:

Take the snippet above, replace the fixed 20/50 SMA windows with parameters you can tweak, and plot the equity curve of a simple long‑only strategy (enter on signal = 1, exit when signal flips to 0). Share your results or a screenshot of the plot in the comments — let’s see who can tune the parameters for the smoothest curve!

Remember, the indicators aren’t crystal balls; they’re lenses. The clearer the lens, the better you can see the path ahead. Happy hunting, and may your crosses be golden and your RSI never stuck in overbought limbo! 🚀

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论