Capstone Backtest: Equal-Weight Portfolio vs SPY in Pandas | Pandas for Finance Ep14

0views
C
CelesteAI
Description
Episode 14 of *Pandas for Finance*. The capstone — a real, end-to-end portfolio backtest assembled from every concept in the previous 13 episodes. The setup: an equal-weight portfolio of five mega-cap tech stocks (AAPL, MSFT, GOOGL, AMZN, NVDA) versus SPY as the benchmark, with 4 percent risk-free rate for the Sharpe calculation. The output: an annualized return, vol, Sharpe, max drawdown, and final wealth multiplier for each side, plus a per-stock Sharpe leaderboard. Mega-cap tech finished at +38.92 percent annualized vs SPY's +16.46 percent — but with higher vol and a deeper drawdown. What You'll Build: - `backtest.py` — load the cached prices, filter to the universe, pivot wide for portfolio math, compute daily returns, build an equal-weight portfolio, and produce a full backtest report. - The pivot pattern: `df[df["Ticker"].isin([...])] .pivot(index="Date", columns="Ticker", values="Adj Close") .ffill()` — wide format makes every per-row portfolio operation a one-liner. - The equal-weight calculation: a `pd.Series` of weights times the daily-returns DataFrame, summed across the row. That's the daily portfolio return in one line. - A reusable `stats(returns)` function that returns annualized return, annualized vol, Sharpe, max drawdown, and final wealth multiplier — five numbers that summarize any return stream. - The per-stock Sharpe leaderboard — sort the same metrics per ticker to see which holdings drive the portfolio's risk-adjusted return. Timestamps: 0:00 - Intro — Episode 14 starts here 0:23 - Preview — equal-weight portfolio vs SPY 1:10 - Open nvim, write backtest.py 1:14 - Display options + constants 1:33 - Load + pivot to wide format 1:55 - Daily returns + equal-weight portfolio 2:18 - The stats function (Sharpe, drawdown, final wealth) 2:46 - Build the comparison report 3:30 - Save and run 3:36 - Backtest report (Portfolio +38.9% vs SPY +16.5%) 4:30 - Recap 5:18 - End screen Key Takeaways: 1. **Pivot to wide for portfolio math.** Filter to the universe + benchmark, then `.pivot(index="Date", columns="Ticker", values="Adj Close")`. Each ticker becomes a column. Every per-row operation — daily returns, weighted sums, correlation — becomes vectorized. `.ffill()` after the pivot fills any gaps that come from one ticker being missing on a date the others traded. 2. **Equal-weight portfolio in two lines.** `weights = pd.Series(1 / N, index=tickers)`; `port_ret = (returns[tickers] * weights).sum(axis=1)`. That's it. No loops, no broadcasting tricks — pandas aligns the weights Series to the columns of the returns DataFrame automatically. For other weight schemes (market-cap, risk-parity, momentum), only the `weights` line changes. 3. **A reusable `stats()` function for any return stream.** Annualized return is `(1 + mean) ** 252 - 1`. Annualized vol is `std * sqrt(252)`. Sharpe is `(ann_return - rf) / ann_vol`. Max drawdown is `(wealth / wealth.expanding().max() - 1).min()`. Final wealth is `wealth.iloc[-1]`. Five lines, every metric a quant report needs. 4. **Compare portfolio to benchmark in one DataFrame.** `pd.DataFrame({"Portfolio": stats(port_ret), "SPY": stats(bench_ret)})` — two named columns, five rows of metrics, a single print. The whole thesis of "did mega-cap tech beat the market?" answered in one table. 5. **The per-stock Sharpe leaderboard tells you what's driving the portfolio.** Sort the ticker-level Sharpe ratios — NVDA at +1.48 carries the equal-weight portfolio. AMZN at +0.64 is exactly SPY's Sharpe — a drag in this universe. This decomposition is how you decide whether to drop the laggards in the next iteration. This channel is run by Claude AI. Tutorials AI-produced; reviewed and published by Codegiz. Source code at codegiz.com. #Pandas #Python #Finance #Backtest #Portfolio #Sharpe #DataAnalytics #PythonForFinance #LearnPandas #ClaudeAI
Back to tutorials

Duration

Added to Codegiz

May 10, 2026

📖 Read the articleOpen in YouTube