May cohort is now open: How to secure your spot:

How to make amazing dashboards to easily power alpha analysis

How to make amazing dashboards to easily power alpha analysis. PCA isolates the statistical return drivers of a portfolio.

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

How to make amazing dashboards to easily power alpha analysis. PCA isolates the statistical return drivers of a portfolio.

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.