MA2830 — Portfolio Hedging (Tableau Assignment)
Last updated: Nov 16, 2025, 23:00 SGTFinance Crash Course (Start Here)
Open/Close Crash Course
Motivation — Why hedge?
Ticker choice: Any liquid portfolio ticker with a sensible hedge is acceptable. Any tickers shown are examples only, not required.
Important for grading: In this assignment you are always working with two instruments:
- a Portfolio ticker (what you are trying to protect), and
- a Hedge ticker (the instrument you use to reduce risk).
You must clearly identify these in your data pipeline, Tableau dashboards, and written report using the following format:
Portfolio instrument: <PORTFOLIO_TICKER>
Hedge instrument: <HEDGE_TICKER>
- Big losses kill compounding. A hedge aims to reduce the worst falls so you can stay invested.
- We compare three paths: Unhedged, Static (fixed ratio), Dynamic (rolling beta).
Key ideas
- Return = today/prev − 1; Volatility = day-to-day wiggle; Drawdown = drop from prior peak.
- Correlation (−1→+1) and Beta (slope) tell how portfolio moves vs hedge.
- Static hedge: one fixed ratio daily (e.g., 1.0). Dynamic hedge: use recent beta each day.
- Sharpe proxy = Annual Return / Annual Volatility (return per unit of wiggle).
Math you’ll implement
- Daily return:
today/prev - 1 - Static hedged:
port_r - ratio * hedge_r - Dynamic hedged:
port_r - beta90_clamped * hedge_r - Equity:
100 * EXP(RUNNING_SUM(LOG(1 + r))) - Drawdown:
equity / WINDOW_MAX(equity) - 1 - Annual return:
EXP(AVG(LOG(1+r))*252)-1; Annual vol:STDEV(r)*SQRT(252)
Static vs Dynamic — When each wins / loses
Quick idea: Static = fixed hedge size (your Hedge Ratio parameter). Dynamic = use the recent Rolling Beta (90d) (clamped 0–1.5) as the hedge size.
Static tends to win when…
- Regime is steady: Relationship between portfolio & hedge is stable (beta ~ constant).
- Transaction costs / friction matter: You prefer no daily resizing.
- Signal is noisy: Rolling beta is jumpy; fixed size avoids over-reacting.
Dynamic tends to win when…
- Regime drifts: Beta trends up/down across months; dynamic tracks it.
- Market mix changes: Correlation/volatility shift (e.g., rotations, macro shocks).
- Risk focus: You want the hedge to scale automatically with current sensitivity.
Dynamic can lose when…
- Very fast shocks: Beta estimate lags reality → mis-sized hedge in the moment.
- Beta flips sign briefly: Noise can produce negative/huge betas — clamp (0–1.5) prevents blow-ups.
- Overfitting short windows: Too small a window chases noise; keep ~90 days.
Read your dashboards: Use D2 Rolling Beta to spot regime drift; compare KPIs in D3 Static vs Dynamic; confirm protection in shock windows via D5 Stress.
Tiny example: If 90-day beta ~0.6, Dynamic hedges less than Static 1.0, keeping more upside in calm periods. If beta rises toward 1.2, Dynamic hedges more, cutting drawdowns.
Upfront Assessment (Exploratory Visuals)
Goal: Build quick intuition about your chosen Portfolio and Hedge before hedging.
- Monthly Return Heatmap (Highlight Table) — rows = Year, cols = Month, color = Avg Monthly Return of Portfolio.
- Daily Return Box Plot by Month — distribution of Portfolio daily returns by Month.
- Daily Return Histogram — frequency of Portfolio daily returns.
- Rolling 90-day Correlation Heatmap — Portfolio Return vs Hedge Return (−1→+1).
Upfront EDA — Guiding Questions (answer in captions)
- Which months are typically strongest/weakest for the Portfolio? (Heatmap)
- Which months show the widest spread or most outliers? (Box plot)
- Is the return distribution symmetric or skewed? (Histogram)
- When does correlation with the hedge strengthen or weaken? (Rolling correlation)
- Given these patterns, what hedge ratio might work better: lower, ~1.0, or higher?
Get Live Data (choose one)
Very important: You must pick and clearly document exactly two traded instruments:
- Portfolio ticker – the asset or portfolio you are hedging (e.g.
META,AAPL, a sector ETF). - Hedge ticker – the instrument you use as the hedge (e.g.
SPY,QQQ,IWM,STI ETF).
In your report and in your Tableau story (D1 Overview), you must state:
Portfolio instrument: <PORTFOLIO_TICKER>
Hedge instrument: <HEDGE_TICKER>
These tickers must match across:
- your data pipeline (Google Sheet or Python),
prices_clean.csv, and- your Tableau dashboards (especially D1 Overview title/subtitle).
If it is unclear which tickers were used, marks will be deducted.
A. Google Sheets (no code)
- Create tabs:
PORT,HEDGE,MERGE. Put tickers inPORT!A1andHEDGE!A1. - In
PORT!A3paste:=QUERY(GOOGLEFINANCE($A$1,"close",EDATE(TODAY(),-36),TODAY()), "select Col1,Col2 where Col2 is not null label Col1 'Date', Col2 'Close'",1) - Repeat same in
HEDGE!A3. - In
MERGE!A2paste:
Download MERGE as=QUERY({PORT!A3:B, ARRAYFORMULA(IFNA(VLOOKUP(PORT!A3:A, HEDGE!A3:B, 2, FALSE)))}, "select Col1,Col2,Col3 where Col3 is not null label Col1 'Date', Col2 'PortfolioClose', Col3 'HedgeClose'",0)prices_clean.csv.
B. Python (yfinance, ~10 lines)
import yfinance as yf, pandas as pd
PORT, HEDGE = "QQQ", "SPY"
end = pd.Timestamp.today().normalize(); start = end - pd.DateOffset(months=36)
def pull(t):
df = yf.download(t, start=start, end=end, interval="1d", auto_adjust=True)[["Close"]]
return df.reset_index().rename(columns={"Close":t})
df = pull(PORT).merge(pull(HEDGE), on="Date", how="inner")
df = df.rename(columns={PORT:"PortfolioClose", HEDGE:"HedgeClose"})
df.to_csv("prices_clean.csv", index=False)
Tableau Steps (calculated fields)
- Portfolio Return:
( SUM([PortfolioClose]) / LOOKUP(SUM([PortfolioClose]), -1) ) - 1 - Hedge Return:
( SUM([HedgeClose]) / LOOKUP(SUM([HedgeClose]), -1) ) - 1 - Parameter: Hedge Ratio (0.00–1.50, step 0.10)
- Hedged Return (Static):
[Portfolio Return] - [Hedge Ratio] * [Hedge Return] - Rolling Beta (90d):
WINDOW_COVAR([Portfolio Return],[Hedge Return], -89, 0) / WINDOW_VAR([Hedge Return], -89, 0) - Beta Clamped:
MIN(1.5, MAX(0, [Rolling Beta (90d)])) - Hedged Return (Dynamic):
[Portfolio Return] - [Beta Clamped] * [Hedge Return] - Equity (per series):
100 * EXP(RUNNING_SUM(LOG(1+[Return Series]))) - Drawdown (per series):
[Equity] / WINDOW_MAX([Equity]) - 1 - KPIs (per series): Ann Return, Ann Vol, Max DD, Sharpe = Return/Vol. Compute Using: Date.
Implementation (Tableau-ready)
Purpose: exact fields and settings so your Tableau workbook works on first try.
0) Expected columns
- Date (continuous, ascending)
- PortfolioClose (your chosen asset’s close)
- HedgeClose (hedge benchmark’s close)
Recommended extra columns (for clarity and grading):
PortfolioTicker– constant string column with your portfolio ticker (e.g.META).HedgeTicker– constant string column with your hedge ticker (e.g.QQQ).
These should match the instruments stated in your report and your Tableau titles. If they are inconsistent or missing, marks may be deducted.
1) Daily returns
[Portfolio Return] = ( SUM([PortfolioClose]) / LOOKUP(SUM([PortfolioClose]), -1) ) - 1
[Hedge Return] = ( SUM([HedgeClose]) / LOOKUP(SUM([HedgeClose]), -1) ) - 1
Compute Using: Date (table down). First row null is expected.
2) Rolling beta (90-day)
[Rolling Beta (90d)] =
WINDOW_COVAR( [Portfolio Return], [Hedge Return], -89, 0 )
/
WINDOW_VAR ( [Hedge Return], -89, 0 )
Place on Rows vs Date. Compute Using: Date. Optional regime color:
IF [Rolling Beta (90d)] > 1.2 THEN "High (>1.2)" ELSE "OK" END
3) Strategy returns
[Hedged Return (Static)] = [Portfolio Return] - [Hedge Ratio] * [Hedge Return]
[Hedged Return (Dynamic)] = [Portfolio Return] - [Rolling Beta (90d)] * [Hedge Return]
Create a numeric parameter Hedge Ratio (default 1.0), show parameter control.
4) Equity indexing (per series)
Equity = 100 * EXP( RUNNING_SUM( LOG( 1 + [Return Series] ) ) )
PortEquity→[Return Series] = [Portfolio Return]StaticEquity→[Return Series] = [Hedged Return (Static)]DynamicEquity→[Return Series] = [Hedged Return (Dynamic)]
Compute Using: Date. Ensure 1 + [Return Series] > 0.
5) What your dashboards should show
- D1 — Overview: 3 equity lines (indexed to 100) for Unhedged, Static, Dynamic; Hedge Ratio line visible.
Also include the portfolio and hedge tickers in the title or subtitle, e.g. “Portfolio: META | Hedge: QQQ”. - D2 — Rolling Beta: 90-day beta line with regime highlights (e.g., <0.3 and >1.2) and callouts.
- D3 — Static vs Dynamic: KPIs table (CAGR, Vol, Sharpe, MaxDD, Worst 5-day, win rate) + one example where dynamic helps/hurts.
- D4 — Sensitivity (Static): Static hedge ratios 0.5, 0.8, 1.0, 1.2, shown as small multiples or a parameter-driven view.
- D5 — Stress Windows: pick 2–3 shock windows; per-window bars or mini-curves comparing Unhedged vs Static vs Dynamic.
- D6 — Decision: one clincher chart + 3 bullets you can defend: Benefit, Cost, Limitation.
- D7 — Worst 5-day loss (Optional):
Roll5d = WINDOW_SUM([Ret], −4, 0); bar chart of worst 5-day loss per strategy.
6) Common mistakes
- “Calculation contains errors” → add
SUM()when usingWINDOW_*with base fields. - Flat line at 100 → table calc not set to Date.
- Nulls across chart → missing closes or Date not ascending.
Deliverables
- Upfront EDA Dashboard — Monthly Return Heatmap, Box Plot by Month, Histogram, Rolling 90-day Correlation Heatmap (captions answer EDA questions).
- Tableau Storyboard (5–7 story points = 5–7 dashboards). Set Story as default tab; turn off “Show Sheets as Tabs”. Export a PowerPoint (.pptx) of the Story.
- Required Dashboards (used as story points):
- D1 — Overview — Equity curves: Unhedged vs Static vs Dynamic; Hedge Ratio visible; portfolio & hedge tickers shown in title/subtitle.
- D2 — Rolling Beta — 90-day beta line + callouts when beta < 0.3 or > 1.2
- D3 — Static vs Dynamic — KPIs table + one example where dynamic helps/hurts
- D4 — Sensitivity (Static) — ratios 0.5, 0.8, 1.0, 1.2 (small multiples or parameter view)
- D5 — Stress Windows — pick 2–3 shock windows; per-window bars or mini-curves
- D6 — Decision — one key chart + 3 bullets: Benefit, Cost, Limitation
- D7 — Optional — Worst 5-day loss per strategy (bar chart)
- Workbook — .twbx (Tableau Packaged Workbook) ONLY; no Tableau Public links. The .twbx must contain all dashboards and the Story and open offline.
- Instrument disclosure — In your written report (Data & Instruments section) and in D1 Overview, clearly state
Portfolio instrumentandHedge instrumentusing the exact ticker symbols you used in your data pull. - Data file —
prices_clean.csvthat:- contains at least
Date,PortfolioClose,HedgeClose, and - includes explicit ticker identifiers in either:
- the column names themselves (e.g.
META_Close,QQQ_Close), or - additional string columns such as
PortfolioTickerandHedgeTickerrepeated on each row.
- the column names themselves (e.g.
- contains at least
- Write-up — 1,500–2,000 words covering context, definitions, method, KPIs, sensitivity, stress windows, decision, and ≥3 credible references.
Your write-up MUST include a “Data & Instruments” paragraph in the following format (with all placeholders filled in):Data and Instruments. In this project I hedge a long position in <PORTFOLIO_NAME> (ticker: <PORTFOLIO_TICKER>) using <HEDGE_NAME> (ticker: <HEDGE_TICKER>) as the hedge instrument. Daily adjusted closing prices for both tickers were obtained from <DATA_SOURCE> over the period <START_DATE> to <END_DATE>, downloaded using <TOOL_USED: e.g. Google Sheets GOOGLEFINANCE / Python yfinance> and cleaned into a single file prices_clean.csv with columns Date, PortfolioClose and HedgeClose (plus optional helper fields such as Date (Months) and Stress Window). The portfolio series represents the asset I am trying to protect, while the hedge series represents the instrument used to reduce risk; these exact tickers are used consistently in my data pipeline, Tableau workbook and dashboards (D1 Overview in particular).
Grading Rubric (100 pts)
| Component | Pts | Evidence |
|---|---|---|
| Live data pipeline | 15 | Working Sheet/script; correct 36-month window; portfolio & hedge tickers clearly documented and consistent. |
| Clean CSV | 10 | Correct columns; aligned dates; no blanks; ticker identifiers present in headers and/or ticker columns. |
| Upfront EDA visuals | 15 | Heatmap, box plot, histogram, rolling correlation heatmap; captions answer EDA questions. |
| Tableau calcs & settings | 25 | All fields; Compute Using = Date; Rolling window = 90; parameter visible. |
| Dashboard quality | 15 | Readable lines; % formatting; consistent legends; coherent design. |
| Storyboard (5–7 dashboards as story points) | 10 | Clear titles; concise captions; logical flow; Story default; PowerPoint (.pptx) exported; .twbx submitted. |
| Write-up (1,500–2,000 words) | 10 | Context & definitions, method justified, sensitivity & stress test, numeric evidence, ≥3 credible references. |