Mathew K Analytics

Lesson 57 · Finance and Stock Market Analytics

Designing Financial Analytics Dashboards: Principles, Tools, and Best Practices

In this lesson, we will learn how to build interactive finance dashboards using real stock market data. Dashboards help analysts and investors make quick,…

⬇ Download notebookOpen in Colab ↗

📓 Full notebook

Download .ipynb

Designing Financial Analytics Dashboards#

  • In this lesson, we will learn how to build interactive finance dashboards using real stock market data.
  • Dashboards help analysts and investors make quick, informed decisions by visualising key market metrics and trends.
  • You will use Python to fetch, transform, and visualise live dataessential skills in real-world financial analytics.
  • By the end, you will be able to assemble and display valuable analytics for finance using live Python code.
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
import seaborn as sns

Data concepts for financial dashboards#

  • We will use real daily OHLCV (open, high, low, close, volume) data for multiple major stocks.
  • The data is in long format: each row corresponds to one date and one ticker.
  • Key columns include: Date, Ticker, Open, High, Low, Close, Volume.
  • Dashboards display metrics like price trends, daily changes, sector breakdowns, and risk statistics.
  • Common beginner mistakes:
  • - Using incorrectly reshaped data
  • - Plotting with mismatched indexes
  • - Failing to check for missing data
tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA']
ohlcv = yf.download(tickers, period='1y', auto_adjust=True, progress=False)
ohlcv = ohlcv.stack(future_stack=True).rename_axis(['Date','Ticker']).reset_index()
ohlcv.columns.name = None
print('Shape:', ohlcv.shape)
print(ohlcv.head(3))
Shape: (1255, 7)
        Date Ticker       Close        High         Low        Open    Volume
0 2025-07-15   AAPL  208.283691  211.052705  208.094440  208.393257  42296300
1 2025-07-15   AMZN  226.350006  227.270004  225.460007  226.199997  34907300
2 2025-07-15  GOOGL  181.482269  183.695955  181.083413  182.289963  33448300

Beginner Example 1: Filter by ticker#

  • To analyse one company in detail, filter the long data using its ticker symbol.
  • This lets us quickly extract all rows for a selected stock.
aapl = ohlcv[ohlcv['Ticker'] == 'AAPL']
print(aapl.head())
         Date Ticker       Close        High         Low        Open    Volume
0  2025-07-15   AAPL  208.283691  211.052705  208.094440  208.393257  42296300
5  2025-07-16   AAPL  209.329544  211.560683  207.815546  209.468990  47490500
10 2025-07-17   AAPL  209.190109  210.963074  208.761800  209.737939  48068100
15 2025-07-18   AAPL  210.345505  210.953095  208.871357  210.036732  48974600
20 2025-07-21   AAPL  211.640381  214.927344  210.793749  211.261893  51377400

Beginner Example 2: Create a basic price plot#

  • Line charts show changes in stock price over time.
  • This is the most common way to visualise stock movement in a dashboard.
plt.figure(figsize=(10,5))
plt.plot(aapl['Date'], aapl['Close'], label='AAPL Close Price')
plt.title('AAPL Closing Price Over Last Year')
plt.xlabel('Date')
plt.ylabel('Close Price (USD)')
plt.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image

Beginner Example 3: Calculate daily returns#

  • Dashboards often show daily returns the percent change in closing price from one day to the next.
  • This helps investors and analysts quickly spot volatility.
aapl['Daily_Return'] = aapl['Close'].pct_change()*100
print(aapl[['Date','Close','Daily_Return']].head(7))
         Date       Close  Daily_Return
0  2025-07-15  208.283691           NaN
5  2025-07-16  209.329544      0.502129
10 2025-07-17  209.190109     -0.066610
15 2025-07-18  210.345505      0.552318
20 2025-07-21  211.640381      0.615595
25 2025-07-22  213.552795      0.903615
30 2025-07-23  213.303772     -0.116610

Intermediate Example 1: Pivot to wide for multi-ticker displays#

  • Dashboards often need to show price lines for multiple stocks simultaneously.
  • Pivoting reshapes the data so each ticker is a column.
close_wide = ohlcv.pivot(index='Date', columns='Ticker', values='Close')
print(close_wide.head())
Ticker            AAPL        AMZN       GOOGL        MSFT        TSLA
Date                                                                  
2025-07-15  208.283691  226.350006  181.482269  501.811768  310.779999
2025-07-16  209.329544  223.190002  182.449524  501.613342  321.670013
2025-07-17  209.190109  223.880005  183.057770  507.645172  319.410004
2025-07-18  210.345505  226.130005  184.533569  506.008209  329.649994
2025-07-21  211.640381  229.300003  189.559235  506.018158  328.489990
plt.figure(figsize=(10,6))
close_wide.plot(ax=plt.gca())
plt.title('Tech Stock Closing Prices Over Last Year')
plt.ylabel('Close Price (USD)')
plt.xlabel('Date')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
No description has been provided for this image

Intermediate Example 2: Heatmap of daily returns#

  • Correlation heatmaps helps in visualising how stocks move together.
  • It is useful for quickly spotting diversification or concentration risk.
returns = close_wide.pct_change()*100
corr = returns.corr()
plt.figure(figsize=(7,6))
sns.heatmap(corr, annot=True, cmap='coolwarm', fmt='.2f')
plt.title('Correlation Heatmap of Daily Returns')
plt.show()
No description has been provided for this image

Intermediate Example 3: Rolling volatility chart#

  • Volatility (moving standard deviation of returns) is a key measure in dashboards.
  • Rolling volatility shows how risk changes over time.
window = 21  # roughly 1 trading month
volatility = returns.rolling(window).std()
plt.figure(figsize=(10,6))
volatility.plot(ax=plt.gca())
plt.title(f'{window}-Day Rolling Volatility of Daily Returns')
plt.ylabel('Volatility (%)')
plt.xlabel('Date')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()
No description has been provided for this image

Advanced Example 1: Mini-dashboard - summary KPIs table#

  • Financial dashboards often display key summary metrics (KPIs) for decision making.
  • Let us compute total returns, median volatility, and the maximum drawdown for each stock.
kpis = pd.DataFrame(index=close_wide.columns)
kpis['Total Return (%)'] = (close_wide.iloc[-1] / close_wide.iloc[0] - 1) * 100
kpis['Median Volatility'] = returns.rolling(21).std().median()
drawdown = close_wide / close_wide.cummax() - 1
kpis['Max Drawdown (%)'] = drawdown.min() * 100
print(kpis.round(2))
        Total Return (%)  Median Volatility  Max Drawdown (%)
Ticker                                                       
AAPL               51.17               1.48            -13.80
AMZN                9.34               1.75            -21.74
GOOGL              98.10               1.82            -20.37
MSFT              -23.29               1.39            -34.50
TSLA               27.48               2.65            -29.93

Advanced Example 2: Dashboard sector breakdown (mock portfolio)#

  • Real dashboards often show how holdings are split by sector.
  • We will use a simulated but realistic portfolio to create a sector allocation chart.
tickers = ['AAPL','MSFT','GOOGL','AMZN','TSLA','NVDA','META','NFLX','JPM','JNJ']
sector_map = {'AAPL':'Tech','MSFT':'Tech','GOOGL':'Tech','AMZN':'Consumer',
              'TSLA':'Auto','NVDA':'Tech','META':'Tech','NFLX':'Media',
              'JPM':'Finance','JNJ':'Health'}
np.random.seed(42)
data = yf.download(tickers, period='1y', auto_adjust=True, progress=False)['Close']
rows = []
for tk in tickers:
    buy = round(float(data[tk].iloc[0]), 2)
    cur = round(float(data[tk].iloc[-1]), 2)
    rows.append({'ticker': tk, 'shares': int(np.random.randint(5, 100)),
                 'buy_price': buy, 'cur_price': cur, 'sector': sector_map[tk]})
df_portfolio = pd.DataFrame(rows)
df_portfolio['gain_pct'] = np.round((df_portfolio['cur_price'] - df_portfolio['buy_price']) / df_portfolio['buy_price'] * 100, 2)
print(df_portfolio.head())
  ticker  shares  buy_price  cur_price    sector  gain_pct
0   AAPL      56     208.28     314.86      Tech     51.17
1   MSFT      97     501.81     384.93      Tech    -23.29
2  GOOGL      19     181.48     359.51      Tech     98.10
3   AMZN      76     226.35     247.49  Consumer      9.34
4   TSLA      65     310.78     396.18      Auto     27.48
sector_counts = df_portfolio.groupby('sector')['shares'].sum()
plt.figure(figsize=(7,5))
sector_counts.plot(kind='bar', color='teal')
plt.title('Portfolio Share Allocation by Sector')
plt.xlabel('Sector')
plt.ylabel('Total Shares')
plt.tight_layout()
plt.show()
No description has been provided for this image

Advanced Example 3: Export dashboard metrics to file#

  • Saving key dashboard outputs like KPIs allows you to share or archive results.
  • Let us export our KPI table to CSV for report use.
kpis.to_csv('dashboard_kpis.csv')
print('Saved KPI dashboard metrics to dashboard_kpis.csv')
Saved KPI dashboard metrics to dashboard_kpis.csv

Error Handling and Debugging#

  • Beginners often struggle with missing data and mismatched date indexes in finance analytics.
  • We show how to detect, handle, and resolve common issues.
print('Any NA in close_wide? ', close_wide.isna().values.any())
na_counts = close_wide.isna().sum()
if na_counts.any():
    print('Tickers with NA:', na_counts[na_counts>0])
    close_wide = close_wide.fillna(method='ffill')
    print('Filled missing values with previous price')
Any NA in close_wide?  False

Best Practices for Dashboard Code#

  • Use functions to keep repeated code clean and reusable.
  • Always check for missing data before plotting.
  • Use clear chart titles and axis labels so others can understand your work.
  • Set random seed to 42 when randomisation is involved so results are reproducible.
  • Keep code and dashboard metrics in sync to prevent reporting errors.
def plot_dashboard_price(ticker):
    df = ohlcv[ohlcv['Ticker'] == ticker]
    plt.figure(figsize=(9,5))
    plt.plot(df['Date'], df['Close'], label=f'{ticker} Close')
    plt.title(f'{ticker} Dashboard Price Chart')
    plt.xlabel('Date')
    plt.ylabel('Close Price (USD)')
    plt.legend()
    plt.tight_layout()
    plt.show()
plot_dashboard_price('GOOGL')
No description has been provided for this image

Tiny End-to-End Example: Dashboard Snapshots#

  • You will now create a simple dashboard summary: plot, table, and sector split in three lines.
  • This flows from fetching data to dashboardsall in one place.
# Dashboard: 1. Plot all price trends
close_wide.plot(figsize=(10,5), title='All Tech Closing Prices (1yr)')
plt.xlabel('Date'); plt.ylabel('USD'); plt.tight_layout(); plt.show()
# Dashboard: 2. Show key metrics
display(kpis.round(2))
# Dashboard: 3. Portfolio sector pie chart
sector_val = df_portfolio.groupby('sector').apply(lambda d: (d['shares']*d['cur_price']).sum())
sector_val.plot.pie(autopct='%1.1f%%', ylabel='', title='Portfolio Allocation by Sector')
plt.tight_layout(); plt.show()
No description has been provided for this image
Total Return (%) Median Volatility Max Drawdown (%)
Ticker
AAPL 51.17 1.48 -13.80
AMZN 9.34 1.75 -21.74
GOOGL 98.10 1.82 -20.37
MSFT -23.29 1.39 -34.50
TSLA 27.48 2.65 -29.93
No description has been provided for this image
 

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.