Moving averages are everywhere in trading. But which window length actually performs best? I ran a systematic test across five different time horizons to find out.
This article walks through building a weighted moving average backtester in Python. You'll see how different window sizes affect returns, volatility, and drawdowns using real market data.
Most algo trading content gives you theory.
This gives you the code.3 Python strategies. Fully backtested. Colab notebook included.
Plus a free ebook with 5 more strategies the moment you subscribe.5,000 quant traders already run these:
Subscribe | AlgoEdge Insights
What You'll Learn
- What the strategy is
- Why it works
- How to implement it in Python
- How to test it
- What results to expect
Understanding the Idea
Think of a moving average like checking your average monthly spending. You could look at the last 10 days, last 50 days, or even last 200 days. Each gives you a different picture.
A weighted moving average is like caring more about what you spent yesterday than what you spent three months ago. Recent data gets more influence on the final number.
Short windows react quickly to new information. They're like a friend who changes plans the moment something comes up. Long windows are more stable. They're the friend who sticks to the plan unless something major happens.
The tradeoff is simple: quick reactions catch trends early but also catch fake signals. Slow reactions miss the noise but also miss real opportunities.
Finding the right balance is what this analysis is about.
Why This Strategy Can Work
Markets move in trends. When prices start climbing, they often keep climbing for a while. Moving averages help you identify when a trend might be starting or ending.
By weighting recent prices more heavily, WMA responds faster than a simple average. This means you get into trends earlier and out of them sooner.
The key is finding a window that's responsive enough to catch real moves but slow enough to ignore random noise. Different market conditions favor different windows.
Implementation in Python
Calculating a weighted moving average requires assigning decreasing weights to older prices. Here's how to do it:
This function creates weights from 1 to N, where N is your window size. The most recent price gets the highest weight.
Now you have five different WMA columns, each representing a different timeframe perspective.
def calculate_wma(prices, window):
weights = range(1, window + 1)
wma = prices.rolling(window).apply(
lambda x: sum(w * p for w, p in zip(weights, x)) / sum(weights)
)
return wma
# Calculate WMA for multiple windows
windows = [10, 20, 50, 100, 200]
for w in windows:
df[f'wma_{w}'] = calculate_wma(df['close'], w)
Enjoying this strategy so far? This is only a taste of what's possible.
Go deeper with my newsletter: longer, more detailed articles + full Google Colab implementations for every approach.
Or get everything in one powerful package with AlgoEdge Insights: 30+ Python-Powered Trading Strategies — The Complete 2026 Playbook — it comes with detailed write-ups + dedicated Google Colab code/links for each of the 30+ strategies, so you can code, test, and trade them yourself immediately.
Exclusive for readers: 20% off the book with code
MEDIUM20.Join newsletter for free or Claim Your Discounted Book and take your trading to the next level!
Building the Strategy
The trading signal is straightforward: go long when price is above the WMA, stay out when price is below. The critical part is avoiding lookahead bias.
The .shift(1) is essential. Without it, you'd be making decisions using information you wouldn't actually have at trade time. This is how many backtests produce unrealistic results.
def generate_signals(df, window):
wma_col = f'wma_{window}'
# Shift by 1 to prevent seeing future data
df['signal'] = (df['close'].shift(1) > df[wma_col].shift(1)).astype(int)
# Calculate strategy returns
df['strategy_return'] = df['signal'] * df['daily_return']
return df
Backtesting the Idea
To compare strategies fairly, you need consistent metrics. Sharpe ratio measures return per unit of risk. Maximum drawdown shows the worst peak-to-trough loss.
Run this for each window size and compare the results side by side.
def calculate_metrics(returns):
total_return = (1 + returns).prod() - 1
annualized_vol = returns.std() * (252 ** 0.5)
sharpe = (returns.mean() / returns.std()) * (252 ** 0.5)
# Calculate maximum drawdown
cumulative = (1 + returns).cumprod()
running_max = cumulative.cummax()
drawdown = (cumulative - running_max) / running_max
max_drawdown = drawdown.min()
return {
'total_return': total_return,
'sharpe_ratio': sharpe,
'max_drawdown': max_drawdown,
'volatility': annualized_vol
}
Results and Insights
In my testing, the 50-day WMA consistently delivered the best risk-adjusted performance. It captured major trends while filtering out most short-term noise.
The 10-day window generated too many signals. Transaction costs would eat into returns, and whipsaws were frequent during choppy markets.
The 200-day window was too slow. It missed significant portions of uptrends and stayed in positions too long during downturns.
The 50-day sweet spot isn't guaranteed to repeat. But it makes intuitive sense: roughly two months of data balances responsiveness with stability.
Limitations
This analysis has real constraints worth noting:
- Past performance doesn't predict future results. Market regimes change.
- Transaction costs aren't included. Frequent trading erodes returns.
- The test covers only one asset class. Results may differ for stocks, crypto, or forex.
- WMA still lags price action. You'll never catch the exact top or bottom.
- Optimization can lead to curve fitting. The "best" window on historical data might not be best going forward.
Conclusion
Moving average strategies aren't magic. They're tools for systematic decision-making that remove emotion from trading.
The 50-day WMA performed well in this analysis, but the real value is in the framework. You now have a way to test any window length and compare results objectively.
Try extending this to other assets or combining multiple windows. The code is simple enough to modify, and the insights compound as you experiment.
Most algo trading content gives you theory.
This gives you the code.3 Python strategies. Fully backtested. Colab notebook included.
Plus a free ebook with 5 more strategies the moment you subscribe.5,000 quant traders already run these:
Subscribe | AlgoEdge Insights