avatarB/O Trading Blog

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

9585

Abstract

div><div id="1bc3"><pre> <span class="hljs-comment"># Create sub plots</span> fig = make_subplots(rows=<span class="hljs-number">5</span>, cols=<span class="hljs-number">1</span>, subplot_titles=[<span class="hljs-string">f'<span class="hljs-subst">{<span class="hljs-string">", "</span>.join(symbols)}</span> Close Prices'</span>,
<span class="hljs-string">f'<span class="hljs-subst">{<span class="hljs-string">", "</span>.join(symbols)}</span> Scatter Plot'</span>,
<span class="hljs-string">f'<span class="hljs-subst">{<span class="hljs-string">", "</span>.join(symbols)}</span> Pearson Correlation'</span>,
<span class="hljs-string">f'<span class="hljs-subst">{<span class="hljs-string">", "</span>.join(symbols)}</span> Spearman Correlation'</span>,
<span class="hljs-string">f'<span class="hljs-subst">{<span class="hljs-string">", "</span>.join(symbols)}</span> Kendall Correlation'</span>],
specs=[[{<span class="hljs-string">"secondary_y"</span>: <span class="hljs-literal">True</span>}],[{<span class="hljs-string">"secondary_y"</span>: <span class="hljs-literal">True</span>}],[{<span class="hljs-string">"secondary_y"</span>: <span class="hljs-literal">True</span>}],
[{<span class="hljs-string">"secondary_y"</span>: <span class="hljs-literal">True</span>}],[{<span class="hljs-string">"secondary_y"</span>: <span class="hljs-literal">True</span>}]],
vertical_spacing=<span class="hljs-number">0.1</span>, shared_xaxes=<span class="hljs-literal">False</span>)</pre></div><div id="0c70"><pre> <span class="hljs-comment"># Add legend with the support/resistance prices</span> correlation_info = <span class="hljs-string">f"<span class="hljs-subst">{symbols[<span class="hljs-number">0</span>]}</span> avg: <span class="hljs-subst">{<span class="hljs-string">'{:.3f}'</span>.<span class="hljs-built_in">format</span>(stats[<span class="hljs-string">'s1_close_avg'</span>])}</span>, <span class="hljs-subst">{symbols[<span class="hljs-number">1</span>]}</span>: <span class="hljs-subst">{<span class="hljs-string">'{:.3f}'</span>.<span class="hljs-built_in">format</span>(stats[<span class="hljs-string">'s2_close_avg'</span>])}</span><br>"</span> correlation_info += <span class="hljs-string">f"<span class="hljs-subst">{symbols[<span class="hljs-number">0</span>]}</span> std: <span class="hljs-subst">{<span class="hljs-string">'{:.3f}'</span>.<span class="hljs-built_in">format</span>(stats[<span class="hljs-string">'s1_close_std'</span>])}</span>, <span class="hljs-subst">{symbols[<span class="hljs-number">1</span>]}</span>: <span class="hljs-subst">{<span class="hljs-string">'{:.3f}'</span>.<span class="hljs-built_in">format</span>(stats[<span class="hljs-string">'s2_close_std'</span>])}</span><br>"</span> pearson_close_corr = stats[<span class="hljs-string">'s1_s2_corr_pearson'</span>][<span class="hljs-string">'Close_1'</span>][<span class="hljs-number">8</span>] spearman_close_corr = stats[<span class="hljs-string">'s1_s2_corr_spearman'</span>][<span class="hljs-string">'Close_1'</span>][<span class="hljs-number">8</span>] kendall_close_corr = stats[<span class="hljs-string">'s1_s2_corr_kendall'</span>][<span class="hljs-string">'Close_1'</span>][<span class="hljs-number">8</span>] correlation_info += <span class="hljs-string">f"Pearson Close Correlation: <span class="hljs-subst">{<span class="hljs-string">'{:.3f}'</span>.<span class="hljs-built_in">format</span>(pearson_close_corr)}</span><br>"</span> correlation_info += <span class="hljs-string">f"Spearman Close Correlation: <span class="hljs-subst">{<span class="hljs-string">'{:.3f}'</span>.<span class="hljs-built_in">format</span>(spearman_close_corr)}</span><br>"</span> correlation_info += <span class="hljs-string">f"Kendall Close Correlation: <span class="hljs-subst">{<span class="hljs-string">'{:.3f}'</span>.<span class="hljs-built_in">format</span>(kendall_close_corr)}</span><br>"</span></pre></div><div id="e55d"><pre> fig.add_annotation(<span class="hljs-attribute">text</span>=correlation_info, <span class="hljs-attribute">align</span>=<span class="hljs-string">'left'</span>, <span class="hljs-attribute">showarrow</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">xref</span>=<span class="hljs-string">'paper'</span>, <span class="hljs-attribute">yref</span>=<span class="hljs-string">'paper'</span>, <span class="hljs-attribute">x</span>=1.0, <span class="hljs-attribute">y</span>=1.0, <span class="hljs-attribute">bordercolor</span>=<span class="hljs-string">'black'</span>, <span class="hljs-attribute">borderwidth</span>=1, <span class="hljs-attribute">bgcolor</span>=<span class="hljs-string">'white'</span>)</pre></div><div id="8a53"><pre> # <span class="hljs-selector-tag">Prices</span> <span class="hljs-selector-tag">fig</span><span class="hljs-selector-class">.add_trace</span>(go.<span class="hljs-built_in">Scatter</span>(x=s1_s2_scaled_df.index, y=s1_s2_scaled_df[<span class="hljs-string">'Close_1'</span>], line=<span class="hljs-built_in">dict</span>(<span class="hljs-attribute">color</span>=light_palette[<span class="hljs-string">"color_9"</span>], <span class="hljs-attribute">width</span>=<span class="hljs-number">1</span>), name=f<span class="hljs-string">"{symbols[0]} Close"</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>) <span class="hljs-selector-tag">fig</span><span class="hljs-selector-class">.add_trace</span>(go.<span class="hljs-built_in">Scatter</span>(x=s1_s2_scaled_df.index, y=s1_s2_scaled_df[<span class="hljs-string">'Close_2'</span>], line=<span class="hljs-built_in">dict</span>(<span class="hljs-attribute">color</span>=light_palette[<span class="hljs-string">"color_2"</span>], <span class="hljs-attribute">width</span>=<span class="hljs-number">1</span>), name=f<span class="hljs-string">"{symbols[1]} Close"</span>), row=<span class="hljs-number">1</span>, col=<span class="hljs-number">1</span>)</pre></div><div id="e1fd"><pre> # Scatter plot fig.add_trace(go.Scatter(<span class="hljs-attribute">x</span>=s1_s2_scaled_df[<span class="hljs-string">'Close_1'</span>],<span class="hljs-attribute">y</span>=s1_s2_scaled_df[<span class="hljs-string">'Close_2'</span>], <span class="hljs-attribute">mode</span>=<span class="hljs-string">'markers'</span>, <span class="hljs-attribute">marker</span>=dict( <span class="hljs-attribute">color</span>=light_palette[<span class="hljs-string">"color_9"</span>], <span class="hljs-attribute">showscale</span>=<span class="hljs-literal">False</span> )), <span class="hljs-attribute">row</span>=2, <span class="hljs-attribute">col</span>=1)</pre></div><div id="82b9"><pre> # Pearson Heatmap fig.add_trace( go.Heatmap( <span class="hljs-attribute">showscale</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">showlegend</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">xgap</span>=1, <span class="hljs-attribute">ygap</span>=1, <span class="hljs-attribute">x</span>=stats[<span class="hljs-string">'s1_s2_corr_pearson'</span>].columns, <span class="hljs-attribute">y</span>=stats[<span class="hljs-string">'s1_s2_corr_pearson'</span>].index, <span class="hljs-attribute">z</span>=np.array(stats[<span class="hljs-string">'s1_s2_corr_pearson'</span>]) ), <span class="hljs-attribute">row</span>=3, <span class="hljs-attribute">col</span>=1)</pre></div><div id="dbf3"><pre> # Spearman Heatmap fig.add_trace( go.Heatmap( <span class="hljs-attribute">showscale</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">showlegend</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">xgap</span>=1, <span class="hljs-attribute">ygap</span>=1, <span class="hljs-attribute">x</span>=stats[<span class="hljs-string">'s1_s2_corr_spearman'</span>].columns, <span class="hljs-attribute">y</span>=stats[<span class="hljs-string">'s1_s2_corr_spearman'</span>].index, <span class="hljs-attribute">z</span>=np.array(stats[<span class="hljs-string">'s1_s2_corr_spearman'</span>], ) ), <span class="hljs-attribute">row</span>=4, <span class="hljs-attribute">col</span>=1)</pre></div><div id="198a"><pre> # Kendall Heatmap fig.add_trace( go.Heatmap( <span class="hljs-attribute">showscale</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">showlegend</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">xgap</span>=1, <span class="hljs-attribute">ygap</span>=1, <span class="hljs-attribute">x</span>=stats[<span class="hljs-string">'s1_s2_corr_kendall'</span>].columns, <span class="hljs-attr

Options

ibute">y</span>=stats[<span class="hljs-string">'s1_s2_corr_kendall'</span>].index, <span class="hljs-attribute">z</span>=np.array(stats[<span class="hljs-string">'s1_s2_corr_kendall'</span>], ) ), <span class="hljs-attribute">row</span>=5, <span class="hljs-attribute">col</span>=1) </pre></div><div id="6018"><pre> fig.update_layout( title={<span class="hljs-string">'text'</span>: <span class="hljs-string">''</span>, <span class="hljs-string">'x'</span>: 0.5}, <span class="hljs-attribute">font</span>=dict(family="Verdana", <span class="hljs-attribute">size</span>=12, <span class="hljs-attribute">color</span>=palette[<span class="hljs-string">"text_color"</span>]), <span class="hljs-attribute">autosize</span>=<span class="hljs-literal">True</span>, <span class="hljs-attribute">width</span>=1280, <span class="hljs-attribute">height</span>=1280, xaxis={<span class="hljs-string">"rangeslider"</span>: {<span class="hljs-string">"visible"</span>: <span class="hljs-literal">False</span>}}, <span class="hljs-attribute">plot_bgcolor</span>=palette[<span class="hljs-string">"plot_bg_color"</span>], <span class="hljs-attribute">paper_bgcolor</span>=palette[<span class="hljs-string">"bg_color"</span>]) fig.update_yaxes(<span class="hljs-attribute">visible</span>=<span class="hljs-literal">False</span>, <span class="hljs-attribute">secondary_y</span>=<span class="hljs-literal">True</span>) # Change grid color fig.update_xaxes(<span class="hljs-attribute">showline</span>=<span class="hljs-literal">True</span>, <span class="hljs-attribute">linewidth</span>=1, <span class="hljs-attribute">linecolor</span>=palette[<span class="hljs-string">"grid_color"</span>], <span class="hljs-attribute">gridcolor</span>=palette[<span class="hljs-string">"grid_color"</span>]) fig.update_yaxes(<span class="hljs-attribute">showline</span>=<span class="hljs-literal">True</span>, <span class="hljs-attribute">linewidth</span>=1, <span class="hljs-attribute">linecolor</span>=palette[<span class="hljs-string">"grid_color"</span>], <span class="hljs-attribute">gridcolor</span>=palette[<span class="hljs-string">"grid_color"</span>])</pre></div><div id="5500"><pre> <span class="hljs-keyword">return</span> fig</pre></div><p id="5353">Finally, here is the main function, which performs the following steps:</p><ol><li>Download the price data for NASDAQ 100 index (^NDX) and Fastenal (FAST)</li><li>Scale the two data sets</li><li>Concatenate the data sets</li><li>Calculate the statistics and correlation coefficients</li><li>Plot the data</li><li>Start a dash server with the plots to create interactive charts.</li></ol><div id="889d"><pre><span class="hljs-attr">name</span> == <span class="hljs-string">'main'</span>: <span class="hljs-attr">symbols</span> = [<span class="hljs-string">'^NDX'</span>,<span class="hljs-string">'FAST'</span>,]</pre></div><div id="743b"><pre> <span class="hljs-comment"># Download data</span> <span class="hljs-attr">interval</span> = <span class="hljs-string">"1m"</span> <span class="hljs-attr">period</span> = <span class="hljs-string">"2d"</span> <span class="hljs-attr">s1_df</span> = download_data(symbols[<span class="hljs-number">0</span>], interval, period) <span class="hljs-attr">s2_df</span> = download_data(symbols[<span class="hljs-number">1</span>], interval, period)</pre></div><div id="7e14"><pre> <span class="hljs-comment"># Scale data</span> <span class="hljs-attr">s1_scaled_df</span> = scale_data(s1_df, <span class="hljs-number">1</span>) <span class="hljs-attr">s2_scaled_df</span> = scale_data(s2_df, <span class="hljs-number">2</span>)</pre></div><div id="dea5"><pre> # Concatenate data s1_s2_scaled_df = pd.concat([s1_scaled_df, s2_scaled_df], <span class="hljs-attribute">axis</span>=1, <span class="hljs-attribute">ignore_index</span>=<span class="hljs-literal">False</span>)</pre></div><div id="85e5"><pre> <span class="hljs-comment"># Calculate correlation stats</span> <span class="hljs-attr">stats</span> = calculate_stats(s1_s2_scaled_df)</pre></div><div id="f0e4"><pre> <span class="hljs-comment"># Plot the charts</span> <span class="hljs-attr">fig</span> = plot_charts(symbols, s1_s2_scaled_df, stats)</pre></div><div id="0d6c"><pre> app = Dash() app.layout = html.Div(children=[ html.H1(<span class="hljs-attribute">children</span>=<span class="hljs-string">'Correlation Charts'</span>), dcc.Graph( <span class="hljs-attribute">id</span>=<span class="hljs-string">'correlation-graphs'</span>, <span class="hljs-attribute">figure</span>=fig) ]) app.run_server(<span class="hljs-attribute">debug</span>=<span class="hljs-literal">True</span>)</pre></div><p id="705b">Open a browser and paste this URL into the address field: <a href="http://127.0.0.1:8050/">http://127.0.0.1:8050/</a></p><p id="53e4">You should now be able to see the plots in your browser window.</p><h1 id="6e64">Results</h1><h2 id="4cdb">Visual Correlation</h2><p id="dbe3">The easiest way to check the correlation of price data sets is by plotting them out in a chart. By plotting them, we can immediately tell if their price movement are closely related, somewhat or not at all.</p><p id="ba64">In the graph below we plotted 1-minute prices of Fastenal Corporation (FAST) against the NASDAQ Composite Index. Fastenal is part of that index.</p><p id="1bfc">The price data has been normalized to remove the difference in scale between the prices to be compared.</p><p id="9b77">Here you see that the Close price of Fastenal seems to match the Close price of the NASDAQ 100 index very closely.</p><figure id="ea93"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*sS9BhKX6qE3CxGbq.png"><figcaption></figcaption></figure><h1 id="4581">Scatterplots</h1><p id="5107">Another way to analyze linear correlation between two values is to plot them out in a scatter plot.</p><p id="aa2c">When plotting the close prices of Fastenal and the NADAQ 100, we see a clear linear relationship and can imagine a that the dots align with a diagonal line drawn through the center of the dot distribution.</p><figure id="4b26"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*-tvD95x1EFBLjwCM.png"><figcaption></figcaption></figure><h2 id="a074">Pearson Correlation</h2><p id="33ab">The <a href="https://en.wikipedia.org/wiki/Pearson_correlation_coefficient">Pearson correlation</a> — invented by Karl Pearson — is used to assess the quality of a linear relationship between two sets of data. It is calculated as the covariance of the two variables divided by the product of the standard deviation of each data set.</p><p id="c60e">The Pearson value I calculated for Fastenal is 0.783, so a very close positive correlation. This is also apparent in the heatmap below. The map has a light orange color where Close_1 (Fastenal Close) and Close_2 (NADAQ 100) intersect, which indicates a close positive relation.</p><figure id="6876"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*GJcWxQAz-PFVYhJ5.png"><figcaption></figcaption></figure><h2 id="9e28">Spearman Correlation</h2><p id="035b">The <a href="https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient">Spearman Correlation</a> is another measure of the relationship between two variables or data sets invented by Charles Spearman. It assesses how well the relationship between two variables can be described using a <a href="https://en.wikipedia.org/wiki/Monotonic_function">monotonic function</a>. A monotonic function is a function between dataset that preserves or reverses the given order.</p><p id="e2af">As with the Pearson correlation coefficient, the scores range between -1 and 1. The meaning of the range is the same as for the Pearson Correlation.</p><p id="0331">For the Spearman coefficient I calculated for Fastenal was 0.73 so again a high positive correlation.</p><figure id="32dd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*jYvL6riUVFOe83EY.png"><figcaption></figcaption></figure><h2 id="2783">Kendall Correlation</h2><p id="e481">A third method for assessing the relationship between variables is the<a href="https://en.wikipedia.org/wiki/Kendall_rank_correlation_coefficient"> Kendall Correlation rank coefficient</a>, named after Maurice Kendall. It is used to measure the ordinal association between two measured quantities.</p><p id="d8f2">The Kendall coefficient for Fastenal is 0.54, which represents a positive correlation.</p><figure id="5611"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*GCZI3m03tLmp-GNf.png"><figcaption></figcaption></figure><h1 id="8b21">Wrapping Up</h1><p id="fb7e">In this post we looked at the different ways to assess correlation between a market index and stock prices and went over the steps how to perform this analysis in Python.</p><p id="b465">I hope you found this post worth your time. Thanks for reading.</p><p id="1953">You can support my writing for free <a href="https://medium.com/@chris_42047/membership">using this link</a>. Don’t miss another story — <a href="https://medium.com/subscribe/@chris_42047">subscribe to my stories by email</a>. For more premium content, check out my ‘<a href="https://algorithmictrading.substack.com/">B/O Trading Blog</a>’ on Substack.</p><p id="2799"><i>This post contains affiliate marketing links.</i></p><p id="fbc6">Have a great day!</p></article></body>

Analyzing Correlation between Market Index and Stocks — Python Tutorial

Photo by Ilya Pavlow on Unsplash.com

I have recently posted an article on analyzing the correlation between a market index and different stocks.

In this post I’m going to show you step-by-step how to do this analysis in Python.

This story is solely for general information purposes, and should not be relied upon for trading recommendations or financial advice. Source code and information is provided for educational purposes only, and should not be relied upon to make an investment decision. Please review my full cautionary guidance before continuing.

Trade Ideas provides AI stock suggestions, AI alerts, scanning, automated trading, real-time stock market data, charting, educational resources, and more. Get a 15% discount with promo code ‘BOTRADING15’.

Implementation

You can download the complete script from my blog ‘B/O Trading Blog’.

Create a text file called ‘requirments.txt’ and paste the lines in below. Then run ‘pip install -r requirements.txt’.

pandas
pandas_ta
yfinance
numpy
plotly
sklearn
dash

Add the necessary Python imports:

import pandas as pd
import pandas_ta as ta
import yfinance as yf
import numpy as np
import math
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import os
from sklearn.preprocessing import MinMaxScaler
from dash import Dash, html, dcc

This function downloads the price data from Yahoo Finance and prepares it for processing.

def download_data(symbol, interval, period):
    data = yf.download(tickers=symbol, period=period, interval=interval)
    df = pd.DataFrame(data)
    df.dropna(inplace=True)
    df.reset_index(inplace=True)
    df = df.drop('Datetime', axis=1)
    df = df.drop('Adj Close', axis=1)
    return df

In this function we scale the data to values between 0 and 1 to be able to compare them. For this we are using MinMaxScaler from sklearn.

def scale_data(df, index):
    scaler = MinMaxScaler(feature_range=(0, 1))
    df[[f"Open_{index}", f"High_{index}",f"Low_{index}",f"Close_{index}",f"Volume_{index}"]] = \
        scaler.fit_transform(df[["Open", "High","Low","Close","Volume"]])
    #  Drop columns not scaled
    df = df.drop('Open', axis=1)
    df = df.drop('Close', axis=1)
    df = df.drop('High', axis=1)
    df = df.drop('Low', axis=1)
    df = df.drop('Volume', axis=1)
    return df

This function calculates the statistics and the correlation coefficients.

def calculate_stats(s1_s2_scaled_df):
    stats = {}
    stats['s1_close_avg'] = s1_s2_scaled_df['Close_1'].mean()
    stats['s2_close_avg'] = s1_s2_scaled_df['Close_2'].mean()
    stats['s1_close_std'] = s1_s2_scaled_df['Close_1'].std()
    stats['s2_close_std'] = s1_s2_scaled_df['Close_2'].std()
    stats['s1_s2_corr_pearson'] = s1_s2_scaled_df.corr(method="pearson")
    stats['s1_s2_corr_spearman'] = s1_s2_scaled_df.corr(method="spearman")
    stats['s1_s2_corr_kendall'] = s1_s2_scaled_df.corr(method="kendall")
    return stats

This function plots the visualization chart, scatterplot diagram and the heatmaps for the different coefficients.

def plot_charts(symbols, s1_s2_scaled_df, stats):
    light_palette = {}
    light_palette["bg_color"] = "#ffffff"
    light_palette["plot_bg_color"] = "#ffffff"
    light_palette["grid_color"] = "#e6e6e6"
    light_palette["text_color"] = "#2e2e2e"
    light_palette["dark_candle"] = "#4d98c4"
    light_palette["light_candle"] = "#b1b7ba"
    light_palette["volume_color"] = "#c74e96"
    light_palette["border_color"] = "#2e2e2e"
    light_palette["color_1"] = "#5c285b"
    light_palette["color_2"] = "#802c62"
    light_palette["color_3"] = "#a33262"
    light_palette["color_4"] = "#c43d5c"
    light_palette["color_5"] = "#de4f51"
    light_palette["color_6"] = "#f26841"
    light_palette["color_7"] = "#fd862b"
    light_palette["color_8"] = "#ffa600"
    light_palette["color_9"] = "#3295a8"
    palette = light_palette
    #  Create sub plots
    fig = make_subplots(rows=5, cols=1, subplot_titles=[f'{", ".join(symbols)} Close Prices', \
                                                        f'{", ".join(symbols)} Scatter Plot', \
                                                        f'{", ".join(symbols)} Pearson Correlation', \
                                                        f'{", ".join(symbols)} Spearman Correlation', \
                                                        f'{", ".join(symbols)} Kendall Correlation'], \
                        specs=[[{"secondary_y": True}],[{"secondary_y": True}],[{"secondary_y": True}],\
                               [{"secondary_y": True}],[{"secondary_y": True}]], \
                        vertical_spacing=0.1, shared_xaxes=False)
    #  Add legend with the support/resistance prices
    correlation_info = f"{symbols[0]} avg: {'{:.3f}'.format(stats['s1_close_avg'])}, {symbols[1]}: {'{:.3f}'.format(stats['s2_close_avg'])}<br>"
    correlation_info += f"{symbols[0]} std: {'{:.3f}'.format(stats['s1_close_std'])}, {symbols[1]}: {'{:.3f}'.format(stats['s2_close_std'])}<br>"
    pearson_close_corr = stats['s1_s2_corr_pearson']['Close_1'][8]
    spearman_close_corr = stats['s1_s2_corr_spearman']['Close_1'][8]
    kendall_close_corr = stats['s1_s2_corr_kendall']['Close_1'][8]
    correlation_info += f"Pearson Close Correlation: {'{:.3f}'.format(pearson_close_corr)}<br>"
    correlation_info += f"Spearman Close Correlation: {'{:.3f}'.format(spearman_close_corr)}<br>"
    correlation_info += f"Kendall Close Correlation: {'{:.3f}'.format(kendall_close_corr)}<br>"
    fig.add_annotation(text=correlation_info,
                       align='left',
                       showarrow=False,
                       xref='paper',
                       yref='paper',
                       x=1.0,
                       y=1.0,
                       bordercolor='black',
                       borderwidth=1,
                       bgcolor='white')
    #  Prices
    fig.add_trace(go.Scatter(x=s1_s2_scaled_df.index, y=s1_s2_scaled_df['Close_1'], line=dict(color=light_palette["color_9"], width=1), name=f"{symbols[0]} Close"),
                  row=1, col=1)
    fig.add_trace(go.Scatter(x=s1_s2_scaled_df.index, y=s1_s2_scaled_df['Close_2'], line=dict(color=light_palette["color_2"], width=1), name=f"{symbols[1]} Close"),
                  row=1, col=1)
    #  Scatter plot
    fig.add_trace(go.Scatter(x=s1_s2_scaled_df['Close_1'],y=s1_s2_scaled_df['Close_2'], mode='markers', marker=dict(
        color=light_palette["color_9"],
        showscale=False
    )), row=2, col=1)
    #  Pearson Heatmap
    fig.add_trace(
        go.Heatmap(
            showscale=False,
            showlegend=False,
            xgap=1,
            ygap=1,
            x=stats['s1_s2_corr_pearson'].columns,
            y=stats['s1_s2_corr_pearson'].index,
            z=np.array(stats['s1_s2_corr_pearson'])
        ), row=3, col=1)
    #  Spearman Heatmap
    fig.add_trace(
        go.Heatmap(
            showscale=False,
            showlegend=False,
            xgap=1,
            ygap=1,
            x=stats['s1_s2_corr_spearman'].columns,
            y=stats['s1_s2_corr_spearman'].index,
            z=np.array(stats['s1_s2_corr_spearman'],
                       )
        ), row=4, col=1)
    #  Kendall Heatmap
    fig.add_trace(
        go.Heatmap(
            showscale=False,
            showlegend=False,
            xgap=1,
            ygap=1,
            x=stats['s1_s2_corr_kendall'].columns,
            y=stats['s1_s2_corr_kendall'].index,
            z=np.array(stats['s1_s2_corr_kendall'],
                       )
        ), row=5, col=1)
    fig.update_layout(
        title={'text': '', 'x': 0.5},
        font=dict(family="Verdana", size=12, color=palette["text_color"]),
        autosize=True,
        width=1280, height=1280,
        xaxis={"rangeslider": {"visible": False}},
        plot_bgcolor=palette["plot_bg_color"],
        paper_bgcolor=palette["bg_color"])
    fig.update_yaxes(visible=False, secondary_y=True)
    #  Change grid color
    fig.update_xaxes(showline=True, linewidth=1, linecolor=palette["grid_color"], gridcolor=palette["grid_color"])
    fig.update_yaxes(showline=True, linewidth=1, linecolor=palette["grid_color"], gridcolor=palette["grid_color"])
    return fig

Finally, here is the main function, which performs the following steps:

  1. Download the price data for NASDAQ 100 index (^NDX) and Fastenal (FAST)
  2. Scale the two data sets
  3. Concatenate the data sets
  4. Calculate the statistics and correlation coefficients
  5. Plot the data
  6. Start a dash server with the plots to create interactive charts.
__name__ == '__main__':
    symbols = ['^NDX','FAST',]
    #  Download data
    interval = "1m"
    period = "2d"
    s1_df = download_data(symbols[0], interval, period)
    s2_df = download_data(symbols[1], interval, period)
    #  Scale data
    s1_scaled_df = scale_data(s1_df, 1)
    s2_scaled_df = scale_data(s2_df, 2)
    #  Concatenate data
    s1_s2_scaled_df = pd.concat([s1_scaled_df, s2_scaled_df], axis=1, ignore_index=False)
    #  Calculate correlation stats
    stats = calculate_stats(s1_s2_scaled_df)
    #  Plot the charts
    fig = plot_charts(symbols, s1_s2_scaled_df, stats)
    app = Dash()
    app.layout = html.Div(children=[
        html.H1(children='Correlation Charts'),
        dcc.Graph(
            id='correlation-graphs',
            figure=fig)
    ])
    app.run_server(debug=True)

Open a browser and paste this URL into the address field: http://127.0.0.1:8050/

You should now be able to see the plots in your browser window.

Results

Visual Correlation

The easiest way to check the correlation of price data sets is by plotting them out in a chart. By plotting them, we can immediately tell if their price movement are closely related, somewhat or not at all.

In the graph below we plotted 1-minute prices of Fastenal Corporation (FAST) against the NASDAQ Composite Index. Fastenal is part of that index.

The price data has been normalized to remove the difference in scale between the prices to be compared.

Here you see that the Close price of Fastenal seems to match the Close price of the NASDAQ 100 index very closely.

Scatterplots

Another way to analyze linear correlation between two values is to plot them out in a scatter plot.

When plotting the close prices of Fastenal and the NADAQ 100, we see a clear linear relationship and can imagine a that the dots align with a diagonal line drawn through the center of the dot distribution.

Pearson Correlation

The Pearson correlation — invented by Karl Pearson — is used to assess the quality of a linear relationship between two sets of data. It is calculated as the covariance of the two variables divided by the product of the standard deviation of each data set.

The Pearson value I calculated for Fastenal is 0.783, so a very close positive correlation. This is also apparent in the heatmap below. The map has a light orange color where Close_1 (Fastenal Close) and Close_2 (NADAQ 100) intersect, which indicates a close positive relation.

Spearman Correlation

The Spearman Correlation is another measure of the relationship between two variables or data sets invented by Charles Spearman. It assesses how well the relationship between two variables can be described using a monotonic function. A monotonic function is a function between dataset that preserves or reverses the given order.

As with the Pearson correlation coefficient, the scores range between -1 and 1. The meaning of the range is the same as for the Pearson Correlation.

For the Spearman coefficient I calculated for Fastenal was 0.73 so again a high positive correlation.

Kendall Correlation

A third method for assessing the relationship between variables is the Kendall Correlation rank coefficient, named after Maurice Kendall. It is used to measure the ordinal association between two measured quantities.

The Kendall coefficient for Fastenal is 0.54, which represents a positive correlation.

Wrapping Up

In this post we looked at the different ways to assess correlation between a market index and stock prices and went over the steps how to perform this analysis in Python.

I hope you found this post worth your time. Thanks for reading.

You can support my writing for free using this link. Don’t miss another story — subscribe to my stories by email. For more premium content, check out my ‘B/O Trading Blog’ on Substack.

This post contains affiliate marketing links.

Have a great day!

Python Trad
Algorithmic Trading
Automatic Trading
Trading Bo
Recommended from ReadMedium