Returns: Daily, Wealth Curve, Annualized, Sharpe, Drawdown | Pandas for Finance Ep6

0views
C
CelesteAI
Description
Episode 6 of *Pandas for Finance*. The analyst's bread and butter — the return calculation in five flavors. A return is the percent change in price. The episode walks through `df.groupby("Ticker")["Adj Close"].pct_change()` for daily returns on the long-format frame, then `(1 + r).cumprod()` for the wealth curve, then the annualized return, volatility, and Sharpe. We finish with a fourteen-ticker leaderboard ranked by annualized return — NVDA leading at eighty percent, Tesla close behind, Apple third. The four-number performance summary that every strategy report opens with, end-to-end in one script. What You'll Build: - `returns.py` — load the cached prices in long format, compute the per-ticker daily return with `groupby("Ticker")["Adj Close"].pct_change()`, then a wealth curve, then the annualized statistics, then a leaderboard across all fourteen tickers in the cache. - The wealth curve `(1 + return).fillna(0).cumprod()` — what one dollar invested at the start of the period would be worth today. - The annualized return, volatility, and Sharpe ratio — `(1 + mu) ** 252 - 1`, `sigma * sqrt(252)`, `(annual_return - rf) / annual_vol`. - A leaderboard sorted descending by annualized return — built in four chained method calls. Timestamps: 0:00 - Intro — Episode 6 starts here 0:19 - Preview — daily, log, cumulative 0:56 - Open nvim, write returns.py 1:08 - Daily return, grouped by Ticker 1:20 - Wealth curve 1:33 - Annualize: mean × 252, std × √252, Sharpe 1:50 - Leaderboard across 14 tickers 2:04 - Save and run 2:10 - AAPL daily + wealth tail 2:24 - Annualized stats line 2:36 - Leaderboard: NVDA, TSLA, AAPL, … 2:54 - Recap 3:33 - End screen Key Takeaways: 1. **`.pct_change()` is the daily return; `groupby("Ticker").pct_change()` is the long-format daily return.** For a single-ticker frame, `aapl["Adj Close"].pct_change()` works directly. For the long-format universe (one row per Date and Ticker), you must group by Ticker first or the percent change between Ticker A's last row and Ticker B's first row will be a nonsense cross-ticker delta. The blog calls this out as the most common stumble in the chapter — sort by Ticker then Date, group, then `pct_change`. 2. **Wealth curve = `(1 + r).fillna(0).cumprod()`.** The first day's return is `NaN`; without `fillna(0)` the entire `cumprod` poisons to NaN. With it, day one starts at 1.0 (your dollar) and each subsequent day is the running product of growth factors. The wealth curve is the line every backtest report opens with, and it's three method calls. 3. **Annualize with 252 trading days, not 365.** `(1 + daily_mean) ** 252 - 1` is the geometric annualized return. `daily_std * sqrt(252)` is the annualized volatility. Calendar-day annualization understates vol by ~20% because non-trading days compress noise. Trading-day annualization is the convention — every Sharpe ratio you see in a paper or fact sheet uses 252. 4. **Sharpe = `(annual_return - risk_free) / annual_vol`.** The four-number performance summary is annual return, annual vol, max drawdown, Sharpe. Every strategy report leads with these four. Drawdown is `wealth / wealth.expanding().max() - 1` — peak-to-trough decline as a percent. The minimum across the whole series is the worst drawdown. 5. **Always use `Adj Close` for returns — never `Close` — when splits or dividends are involved.** A 4-for-1 stock split looks like a 75% drop on `Close`. `Adj Close` is back-corrected for splits and dividends so historical returns stay comparable. Yahoo Finance gives you both; for performance metrics, `Adj Close`. For "what did it actually trade at on that day," `Close`. The cached parquet preserves both. #Pandas #Python #Finance #Returns #Sharpe #Volatility #DataAnalytics #PythonForFinance #Quant #Backtest