Interactive Tableau dashboard exploring 3 years of ASX stock market performance across 36 tickers and 11 GICS sectors — sector rotation, risk/return analysis, correlation mapping, and macro context, published as a permanent live demo.
Most Tableau portfolio projects are static dashboards over sample data. This project combines a Python data pipeline (live ASX market data via yfinance) with a 9-sheet Tableau workbook that demonstrates the full breadth of Tableau's analytical capabilities — LOD expressions, parameter-driven interactivity, dual-axis charts, correlation analysis, Story narrative, and dashboard filter actions. The data pipeline is reproducible: run one script, get fresh data, refresh the viz.
Six-panel interactive dashboard with sector-click filter actions linking all views:
| Panel | What it shows |
|---|---|
| Sector Treemap | At-a-glance sector performance — sized by volume, colored by cumulative return |
| Sector Rotation | 3-year cumulative return curves for all 11 sectors — shows leadership changes |
| Risk vs Return | Classic scatter — volatility (X) vs avg daily return (Y) with quadrant analysis |
| Top/Bottom Performers | Ranked bar chart of 36 stocks by 3-year cumulative return |
| Macro Overlay | RBA cash rate, CPI, GDP growth, unemployment (2018–2025) |
| Correlation Matrix | 11×11 monthly return correlation heatmap — diversification insight |
Click any sector in the treemap → all other panels filter to that sector.
Four-point story (Tableau's unique feature — no Power BI equivalent):
- The Big Picture — How are ASX sectors performing?
- Winners Rotate — Last year's leaders aren't this year's
- Risk vs Reward — Higher returns come with higher volatility — mostly
- The Macro Context — Rate hikes, inflation, and the ASX
| # | Sheet | Tableau skill demonstrated |
|---|---|---|
| 1 | Sector Treemap | Square mark type, diverging color, size encoding |
| 2 | Stock Explorer | Parameter-driven filter, dual axis (price + MA20), continuous date |
| 3 | Sector Returns | Multi-line comparison, color by dimension, percentage formatting |
| 4 | Correlation Heatmap | Square marks, diverging palette centered at 0, secondary data source |
| 5 | Risk/Return Scatter | Avg aggregation, reference lines (quadrants), detail + label on marks |
| 6 | Top/Bottom Performers | Sorted bar chart, reference line at 0, sector color encoding |
| 7 | Macro Overlay | Measure Names/Values, multi-indicator line chart, secondary data source |
| 8 | Volatility Calendar | Date-part manipulation (month × day), calendar heatmap |
| 9 | MA Crossover Signals | Calculated field (IF/THEN), conditional color, text table layout |
Python script pulls 3 years of daily data for 36 ASX tickers via yfinance, computes derived metrics, and outputs clean CSVs for Tableau.
pip install -r requirements.txt
python scripts/pull_data.py # ~60 seconds → outputs to data/processed/| File | Rows | Purpose |
|---|---|---|
asx_daily.csv |
27,360 | Daily OHLCV + returns, MAs, volatility, relative strength |
sector_daily.csv |
8,360 | Sector-level daily aggregates + cumulative return |
sector_correlation.csv |
121 | 11×11 monthly return correlation matrix (flattened) |
macro_indicators.csv |
8 | Annual Australian macro data (RBA, ABS public sources) |
| Metric | Formula | Tableau use |
|---|---|---|
| Daily Return | close[t] / close[t-1] - 1 |
Scatter Y-axis, calendar heatmap |
| Cumulative Return | close[t] / close[0] - 1 |
Treemap color, sector rotation lines |
| MA 20 / MA 50 | 20/50-day rolling mean | Stock explorer overlay, crossover signals |
| Volatility 20d | std(returns, 20) × √252 |
Scatter X-axis (annualised) |
| RS vs MA50 | close / MA50 - 1 |
Relative strength, crossover signal |
| Skill | Where | Interview talking point |
|---|---|---|
| LOD expressions | {FIXED [Ticker] : MAX(...)} |
"FIXED computes before view-level filters — like a SQL window function" |
| Parameters | Stock Explorer ticker selector | "Parameters drive calculated filters for dynamic interactivity" |
| Dual axis | Price + MA20 overlay | "Synchronised dual axis for comparing measures on different scales" |
| Story Points | 4-point guided narrative | "Tableau's unique narrative feature — no Power BI equivalent" |
| Filter actions | Dashboard sector click | "Source sheet filters all target sheets on the shared dimension" |
| Date-part manipulation | Volatility calendar (month × day) | "Discrete vs continuous date parts for calendar layouts" |
| Diverging palettes | Correlation heatmap, treemap | "Centered at zero to separate positive/negative values" |
| Measure Names/Values | Macro overlay | "Generic approach for displaying multiple measures on shared axis" |
36 ASX tickers across 11 GICS sectors:
| Sector | Tickers |
|---|---|
| Financials | CBA, WBC, NAB, ANZ, MQG |
| Materials | BHP, RIO, FMG, MIN |
| Healthcare | CSL, COH, RMD, SHL |
| Energy | WDS, STO, ORG |
| Information Technology | WTC, XRO, CPU, TNE |
| Consumer Staples | WOW, COL, TWE |
| Consumer Discretionary | WES, ALL, JBH |
| Real Estate | GMG, SCG, GPT |
| Industrials | TCL, BXB |
| Communication Services | TLS, TPG, REA |
| Utilities | AGL, APA |
scripts/
pull_data.py Python pipeline: yfinance → derived metrics → clean CSVs
data/
processed/ output CSVs consumed by Tableau
asx_daily.csv 27,360 rows — daily OHLCV + technicals
sector_daily.csv 8,360 rows — sector aggregates
sector_correlation.csv 121 rows — correlation matrix
macro_indicators.csv 8 rows — annual macro data
requirements.txt yfinance, pandas
.gitignore
README.md
LICENSE
Python · yfinance · pandas · Tableau Desktop · Tableau Public
MIT — see LICENSE.