Principal component analysis (PCA) is used widely in data science. It’s a way to reduce the number of dimensions in a data set.
It’s also used in quant finance to find alpha.
In a stock portfolio, a dimension might be a column of returns for one of the stocks.
Once you get the model built, you could spend your time tweaking the code.
Or, you can do it in an interactive dashboard to power your alpha analysis!
Today, we’ll build a Plotly Dash app that displays information about a factor analysis.
Let’s go!
How to make amazing dashboards to easily power alpha analysis

PCA isolates the statistical return drivers of a portfolio. These drivers are called “alpha factors” (or just factors) because they create returns that are not explained by a benchmark.
Quants use factors in trading strategies.
First, they isolate the components. Then they buy the stocks with the largest exposure to a factor and sell the stocks with the smallest exposure to a factor.
Today, we’ll create a Plotly Dash app that accepts a list of ticker symbols, identifies the principal components of their returns, and generates plots to visualize the top factors.
Imports and set up
All the code we’ll write should be in a Python file called app.py. Make sure you install Dash, Dash Bootstrap Components, and Plotly.
Let’s get the imports out of the way.
import datetime import numpy as np import pandas as pd import dash from dash import dcc, html import dash_bootstrap_components as dbc from dash.dependencies import Input, Output import plotly.graph_objs as go import plotly.io as pio from openbb_terminal.sdk import openbb from sklearn.decomposition import PCA pio.templates.default = "plotly"
Build the app components
Initialize the app and construct the components of the user interface.
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) ticker_field = [ html.Label("Enter Ticker Symbols:"), dcc.Input( id="ticker-input", type="text", ), ] components_field = [ html.Label("Select Number of Components:"), dcc.Dropdown( id="component-dropdown", options=[{"label": i, "value": i} for i in range(1, 6)], value=3, ), ] date_picker_field = [ html.Label("Select Date Range:"), # Label for date picker dcc.DatePickerRange( id="date-picker", start_date=datetime.datetime.now() - datetime.timedelta(365 * 3), end_date=datetime.datetime.now(), # Default to today's date display_format="YYYY-MM-DD", ), ] submit = [ html.Button("Submit", id="submit-button"), ]
Start with the text field to enter the list of ticker symbols, the dropdown to select the number of components, the date picker to select the range of data, and the submit button to run the app.
Combine the form elements and placeholders for visualizations to form the app layout.
app.layout = dbc.Container( [ html.H1("PCA on Stock Returns"), # Ticker Input dbc.Row([dbc.Col(ticker_field)]), dbc.Row([dbc.Col(components_field)]), dbc.Row([dbc.Col(date_picker_field)]), dbc.Row([dbc.Col(submit)]), # Charts dbc.Row( [ dbc.Col([dcc.Graph(id="bar-chart")], width=4), dbc.Col([dcc.Graph(id="line-chart")], width=4), ] ), ] )
Dash lets you build columns and rows in a typical grid layout using Python classes. These are then styled with the Bootstrap style library.
Build the callback
@app.callback( [ Output("bar-chart", "figure"), Output("line-chart", "figure"), ], [Input("submit-button", "n_clicks")], [ dash.dependencies.State("ticker-input", "value"), dash.dependencies.State("component-dropdown", "value"), dash.dependencies.State("date-picker", "start_date"), dash.dependencies.State("date-picker", "end_date"), ], ) def update_graphs(n_clicks, tickers, n_components, start_date, end_date): if not tickers: return {}, {} # Parse inputs from user tickers = tickers.split(",") start_date = datetime.datetime.strptime( start_date, "%Y-%m-%dT%H:%M:%S.%f" ).date() end_date = datetime.datetime.strptime( end_date, "%Y-%m-%dT%H:%M:%S.%f" ).date() # Download stock data data = openbb.economy.index( tickers, start_date=start_date, end_date=end_date ) daily_returns = data.pct_change().dropna() # Apply PCA pca = PCA(n_components=n_components) pca.fit(daily_returns) explained_var_ratio = pca.explained_variance_ratio_ # Bar chart for individual explained variance bar_chart = go.Figure( data=[ go.Bar( x=["PC" + str(i + 1) for i in range(n_components)], y=explained_var_ratio, ) ], layout=go.Layout( title="Explained Variance by Component", xaxis=dict(title="Principal Component"), yaxis=dict(title="Explained Variance"), ), ) # Line chart for cumulative explained variance cumulative_var_ratio = np.cumsum(explained_var_ratio) line_chart = go.Figure( data=[ go.Scatter( x=["PC" + str(i + 1) for i in range(n_components)], y=cumulative_var_ratio, mode="lines+markers", ) ], layout=go.Layout( title="Cumulative Explained Variance", xaxis=dict(title="Principal Component"), yaxis=dict(title="Cumulative Explained Variance"), ), ) return bar_chart, line_chart if __name__ == "__main__": app.run_server(debug=True)
This code implements a callback function, update_graphs, which ties our user inputs to the visualization outputs.
Every time the user presses the submit button, this function fetches the data, performs the PCA, and updates the visualizations.
You define a callback by using the callback decorator provided by Dash.
This decorator specifies which component properties to watch (Input) and which to update (Output). In our app, clicking the submit button triggers the callback function.
The callback parses the user inputs, downloads data, completes PCA, and generates the visualizations.
When you’re ready, to to the command line and run python app.py. Then open your browser to the URL that prints on the screen.