Lighting Candles

By Yeo Yong Kiat in Finanalytics

10 min read
Candlestick charts offer more information than the typical line chart - through inclusion of the daily high, open, close and low prices, you will know whether buyers or sellers have owned the day. Plotly includes a candlestick plotting module for easy candlestick charts.

(If you haven't yet seen the previous post, I recommend taking a look for a quick intro to candlesticks.)

A Typical Candlestick Chart

In this post, I will explain how to obtain the following candlestick chart plot via the Plotly library in Python. Unlike previous posts, I've removed the rangeslider (which to be honest, is not a very useful feature to have in a trading chart), and I've replaced it with a more useful volume bar chart. Recall that the strength of a candle is also correlated with the volume - the larger the volume, the stronger the candle's indication of the market sentiment.

System Setup

As usual, we'll be working with yfinance, plotly and pandas, and we'll be using TSLA stock data (because I'm invested in it at the moment). However, note that we will not be using the simple high-level Plotly Express - we'll be using "plotly.graph_objects" instead. We will also be calling in the "plotly.subplots" module to help us generate a volume subplot later. Let's get right into it:

## Loading Libraries
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import yfinance as yf

## Accessing stock price data from yfinance
tsla_df=yf.download(
    tickers="TSLA", 
    period="ytd",     
    interval="1d",    
    progress=False,   
    auto_adjust=True  
)

## I prefer to change the "date" index into a column
tsla_df = tsla_df.reset_index()

Creating the Plotly Object

This will be our first composite chart with subplots, so let's break it down:

  • Formatting Subplots: Let's first make the subplot region by creating 2 rows - the top row will hold the candlestick chart, and the bottom row will contain the volume chart. We create the candlestick chart and place it in row 1; then we create the volume chart and place it in row 2.
  • Creating the Candlestick Chart: We invoke the "Candlestick" method and reference the four sets of data that we need from the dataframe.
  • Creating the Volume Chart: We add another trace - but instead of a line chart, we create a bar chart.
  • Formatting the Chart: A simple affair of tweaking the colours and design of the chart.

## Creating the Plotly chart object
# Step 1 - Create a subplot map with 2 rows
fig=make_subplots(
    rows=2, 
    cols=1, 
    shared_xaxes=True, 
    vertical_spacing=0.1,
    row_width = [0.2, 0.7]
)


# Step 2 - Create the candlestick chart
fig.add_trace(go.Candlestick(x=tsla_df['Date'],
                             open=tsla_df['Open'],
                             high=tsla_df['High'],
                             low=tsla_df['Low'],
                             close=tsla_df['Close'], 
                             showlegend=False,
                             name="Price"),
                             row=1, col=1
)

# Step 3 - Create the volume chart
fig.add_trace(
    go.Bar(
        x = tsla_df["Date"], 
        y = tsla_df["Volume"], 
        showlegend=False,
        marker_color="grey",
        name="Volume"
        ), 
    row=2, col=1
)

# Step 4 - format the layout
fig.update_layout(
    font_color="white",

    xaxis_title="<b>Date</b>", 
    xaxis_gridcolor="#272822",

    yaxis1_title="<b>Price</b>",
    yaxis2_title="<b>Volume</b>",
    yaxis1_gridcolor="#272822",
    yaxis2_gridcolor="#272822",
    
    title="<b>Tesla Stock Price (YTD, 15 Jun 2022)</b>",
    title_font_size=20,
    title_x=0.5,
    paper_bgcolor='#272822',
    plot_bgcolor='#272822',

    xaxis_rangeslider_visible=False
)

This should yield you the following simple chart:

Removing Data Gaps

You'll notice that the candlestick chart is not quite perfect yet - see the gaps between the bars and some sections of the candlestick chart? That's because no data exists for those dates! Those dates correspond to public holidays, weekends and other market closure dates. We will therefore need to tell Plotly to hide those dates from display. I will do this in two ways, via the "rangebreaks" parameter:

  • Using the keyword "bounds" and defining a weekend range: this will hide all weekend days.
  • Using the keyword "values" and defining all the public holiday dates: this will hide all public holidays.

# Step 5 - remove the dates where
# stock data is unavailable

holidays=[             # public holidays
    "2022-01-17", 
    "2022-01-18", 
    "2022-02-21", 
    "2022-04-15", 
    "2022-05-30",
    "2022-06-20"
]

weekend=["sat", "mon"] # weekend range

fig.update_xaxes(
    rangebreaks = [
    dict(values = holidays),
    dict(bounds = weekend)
    ]
)

And there you go, your very own interactive candlestick chart to play with. Enjoy!

Again, the full Python code in all its glory:

## Loading Libraries
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import yfinance as yf

## Accessing stock price data from yfinance
tsla_df=yf.download(
    tickers="TSLA", 
    period="ytd",     
    interval="1d",    
    progress=False,   
    auto_adjust=True  
)

## I prefer to change the "date" index into a column
tsla_df = tsla_df.reset_index()

## Creating the Plotly chart object
# Step 1 - Create a subplot map with 2 rows
fig=make_subplots(
    rows=2, 
    cols=1, 
    shared_xaxes=True, 
    vertical_spacing=0.1,
    row_width = [0.2, 0.7]
)


# Step 2 - Create the candlestick chart
fig.add_trace(go.Candlestick(x=tsla_df['Date'],
                             open=tsla_df['Open'],
                             high=tsla_df['High'],
                             low=tsla_df['Low'],
                             close=tsla_df['Close'], 
                             showlegend=False,
                             name="Price"),
                             row=1, col=1
)

# Step 3 - Create the volume chart
fig.add_trace(
    go.Bar(
        x = tsla_df["Date"], 
        y = tsla_df["Volume"], 
        showlegend=False,
        marker_color="grey",
        name="Volume"
        ), 
    row=2, col=1
)

# Step 4 - format the layout
fig.update_layout(
    font_color="white",

    xaxis_title="Date", 
    xaxis_gridcolor="#272822",

    yaxis1_title="Price",
    yaxis2_title="Volume",
    yaxis1_gridcolor="#272822",
    yaxis2_gridcolor="#272822",
    
    title="Tesla Stock Price (YTD, 15 Jun 2022)",
    title_font_size=20,
    title_x=0.5,
    paper_bgcolor='#272822',
    plot_bgcolor='#272822',

    xaxis_rangeslider_visible=False
)

# Step 5 - remove the dates where
# stock data is unavailable

holidays=[             # public holidays
    "2022-01-17", 
    "2022-01-18", 
    "2022-02-21", 
    "2022-04-15", 
    "2022-05-30",
    "2022-06-20"
]

weekend=["sat", "mon"] # weekend range

fig.update_xaxes(
    rangebreaks = [
    dict(values = holidays),
    dict(bounds = weekend)
    ]
)
Great! Now how do I know what patterns to look out for?

Find more Finalytics stories on my blog. Have a suggestion? Contact me at [email protected].