Skip to contents

Introduction

This vignette explains how to calculate and interpret common financial indicators used in technical analysis. We’ll cover the mathematics behind each indicator and demonstrate the functions used to calculate them as well as leverage those provided by dmplot. Finally, we’ll demonstrate how to visualise these indicators using the dmplot package.

Licensing

The dmplot package is released under the MIT license, allowing free use and modification. Users must:

  1. Cite the original author (see LICENSE for details).
  2. Include the license in any redistribution.

Setup

See the getting started for installing the recommended libraries: Getting Started with The dmplot Framework

box::use(dt = data.table)
box::use(ggplot2)
box::use(dmplot)

Loading Sample Data

We’ll use the same sample data as in the README:

ticker <- "BTC/USDT"

data <- get_market_data(
    symbols = ticker,
    from = lubridate::now() - lubridate::days(7),
    to = lubridate::now(),
    frequency = "1 hour"
)
head(data)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 1 variable(s) not shown: [turnover <num>]

Calculating and Visualising Financial Indicators

Being that we adhere to “Tidy Data” principles and the ggplot2 framework we can easily calculate and build our visualisations in layers.

The first set is to create a set of base layers we then reuse throughout the visualisations.

Base Layers

Candlestick Chart

A candlestick chart is a type of financial chart used to represent price movements in a security. Each candlestick typically shows the open, high, low, and close prices for a specific period.

candle_plot <- data |>
    ggplot2$ggplot(ggplot2$aes(
        x = datetime,
        open = open,
        high = high,
        low = low,
        close = close
    )) +
    ## ------------------------------------
    dmplot$stat_candlestick() +
    ## ------------------------------------
    ggplot2$scale_x_datetime(date_breaks = "1 day", date_labels = "%b %d") +
    ggplot2$labs(
        title = paste(ticker, "- Candlestick with EMA and Bollinger Bands"),
        x = "Date",
        y = "Price (USD)"
    ) +
    dmplot$theme_dereck_dark() +
    ggplot2$theme(axis.text.x = ggplot2$element_text(angle = 45, hjust = 1))

print(candle_plot)

Line Chart

Sometimes we may want to visualise a single indicator or price movement over time. A line chart is a simple and effective way to do this.

line_plot <- data |>
    ggplot2$ggplot(ggplot2$aes(
        x = datetime,
        y = close
    )) +
    ggplot2$geom_line(
        colour = "cyan",
        linewidth = 1.25,
        alpha = 0.5,
        na.rm = TRUE
    ) +
    ggplot2$scale_x_datetime(date_breaks = "1 day", date_labels = "%b %d") +
    ggplot2$labs(
        title = paste(ticker, "- Closing Price"),
        x = "Date",
        y = "Price (USD)"
    ) +
    dmplot$theme_dereck_dark() +
    ggplot2$theme(axis.text.x = ggplot2$element_text(angle = 45, hjust = 1))

print(line_plot)

Volume

The volume indicator is not a financial indicator per se, but it is commonly used in conjunction with other indicators to confirm price trends.

volume_plot <- data |>
    ggplot2$ggplot(ggplot2$aes(
        x = datetime,
        y = volume,
        group = symbol
    )) +
    ggplot2$geom_bar(
        stat = "identity",
        ggplot2$aes(fill = ifelse(close > open, "green", "red")),
        linewidth = 1,
        alpha = 1,
        na.rm = TRUE
    ) +
    ggplot2$scale_x_datetime(
        date_breaks = "1 day",
        date_minor_breaks = "1 hour",
        date_labels = "%d %b"
    ) +
    ggplot2$scale_fill_identity() +
    ggplot2$labs(
        x = ggplot2$element_blank(),
        y = "Volume"
    ) +
    dmplot$theme_dereck_dark() +
    ggplot2$theme(
        axis.text.x = ggplot2$element_text(angle = 45, hjust = 1),
        panel.grid.minor = ggplot2::element_blank()
    )

print(volume_plot)

1. Simple Moving Average (SMA)

The Simple Moving Average (SMA) is the average of a security’s price over a specified number of periods.

Mathematics: for a series Y, the SMA at time t is calculated as:

\[ SMA(t) = \frac{Y(t) + Y(t-1) + ... + Y(t-n+1)}{n} \]

where n is the number of periods.

sma <- function(x, n) {
    return(as.list(as.data.frame(TTR::SMA(x, n = n))))
}

data2 <- dt$copy(data)

data2[, sma_short := sma(close, n = 20)[[1]]]
data2[, sma_long := sma(close, n = 50)[[1]]]

head(data2)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 3 variable(s) not shown: [turnover <num>, sma_short <num>, sma_long <num>]

Now using the candlestick plot we created earlier, we can add the SMA layer to visualise the moving averages.

sma_layer <- dmplot$stat_movingaverages(data = data2,
        ggplot2$aes(x = datetime, short = sma_short, long = sma_long),
        alpha = list(mavg = 0.5)
    )

print(candle_plot + sma_layer)

Candlestick Chart with EMA and Bollinger Bands

1. Exponential Moving Average (EMA)

The EMA gives more weight to recent prices, making it more responsive to new information than a simple moving average.

Mathematics: for a series Y, the EMA at time t is calculated as:

\[ EMA(t) = α * Y(t) + (1 - α) * EMA(t-1) \]

where α = 2 / (N + 1), and N is the number of periods.

ema <- function(x, n, wilder = TRUE) {
    as.list(as.data.frame(TTR::EMA(x, n = n, wilder = wilder)))
}

data2 <- dt$copy(data)

data2[, `:=`(
    ema_short = ema(close, n = 10, wilder = TRUE)[[1]],
    ema_long = ema(close, n = 50, wilder = TRUE)[[1]]
)]

head(data2)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 3 variable(s) not shown: [turnover <num>, ema_short <num>, ema_long <num>]
ema_layer <- dmplot$stat_movingaverages(data = data2,
        ggplot2$aes(x = datetime, short = ema_short, long = ema_long),
        alpha = list(mavg = 0.5),
        colour = list("cyan", "magenta")
    )

print(candle_plot + ema_layer)

2. Bollinger Bands

Bollinger Bands consist of a middle band (usually a simple moving average) and an upper and lower band that are standard deviations away from the middle band.

Mathematics:

\[ Middle Band = SMA(n) \] \[ Upper Band = SMA(n) + k * σ(n) \] \[ Lower Band = SMA(n) - k * σ(n) \]

where SMA(n) is the n-period simple moving average, σ(n) is the n-period standard deviation, and k is the number of standard deviations (usually 2).

bb <- function(close, n = 20, sd = 2) {
    as.list(as.data.frame(TTR::BBands(close, n = n, sd = sd)))
}

data2 <- dt$copy(data)

data2[, c("bb_lower", "bb_mavg", "bb_upper", "bb_pct") := bb(close, n = 10, sd = 2)]

head(data2)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 5 variable(s) not shown: [turnover <num>, bb_lower <num>, bb_mavg <num>, bb_upper <num>, bb_pct <num>]

As you can see in the plot below Bolllinger Bands are a great way to visualise price volatility and see when a security is overbought or oversold.

bb_layer <- dmplot$stat_bollingerbands(data = data2,
        ggplot2$aes(ymin = bb_lower, mavg = bb_mavg, ymax = bb_upper),
        colour = list("pink", "cyan", "cyan")
    )

print(candle_plot + bb_layer)

3. Fibonacci Retracement (Fib)

Fibonacci retracement is a popular tool used in technical analysis to identify potential support and resistance levels based on the Fibonacci sequence.

Mathematics:

The Fibonacci retracement levels are calculated as follows:

  • 0.000 (0.0%)
  • 0.236 (23.6%)
  • 0.382 (38.2%)
  • 0.500 (50.0%)
  • 0.618 (61.8%)
  • 0.786 (78.6%)
  • 1.000 (100.0%)
data2 <- dt$copy(data)

high_price <- max(data2$high)
low_price <- min(data2$low)

fib_levels <- dmplot$fib(high_price, low_price)

print(fib_levels)
#> $levels
#> [1] 0.000 0.236 0.382 0.500 0.618 0.786 1.000
#> 
#> $prices
#> [1] 59598.90 58343.88 57567.46 56939.95 56312.44 55419.03 54281.00

In the plot we overlay the Fibonacci retracement levels on the candlestick chart to identify potential support and resistance levels.

fib_plot <- candle_plot +
    ggplot2$geom_hline(
        yintercept = fib_levels$prices, color = "yellow", linetype = "dashed"
    ) +
    ggplot2$scale_y_continuous(
        name = "Price",
        sec.axis = ggplot2$sec_axis(
            ~ (. - low_price) / (high_price - low_price) * 100,
            name = "Retracement %",
            labels = \(x) paste0(round(x, 1), "%")
        )
    ) +
    ggplot2$labs(
        title = "Price Chart with Fibonacci Retracement Levels",
        x = "Date"
    )

print(fib_plot)

4. Moving Average Convergence Divergence (MACD)

MACD is a trend-following momentum indicator that shows the relationship between two moving averages of a security’s price.

Mathematics:

\[ MACD Line = EMA(12) - EMA(26) \] \[ Signal Line = EMA(9) of MACD Line \] \[ MACD Histogram = MACD Line - Signal Line \]

The MACD Line is the difference between a short-term EMA (12 periods) and a long-term EMA (26 periods). The Signal Line is the EMA of the MACD Line (usually 9 periods).

When the MACD Line crosses above the Signal Line, it is considered a bullish signal. When the MACD Line crosses below the Signal Line, it is considered a bearish signal.

macd <- function(x, fast = 12, slow = 26, signal = 9) {
    as.list(as.data.frame(TTR::MACD(x, fast, slow, signal)))
}

data2 <- dt$copy(data)

data2[, c("macd", "macd_signal") := macd(close, fast = 12, slow = 26, signal = 9)]
data2[, macd_diff := macd - macd_signal]

head(data2)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 4 variable(s) not shown: [turnover <num>, macd <num>, macd_signal <num>, macd_diff <num>]

As you can see in the plot below, the MACD indicator is a great way to visualise the relationship between two moving averages and identify potential buy or sell signals.

Our plot below shows the two moving averages and the MACD histogram; the histogram is the difference between the MACD Line and the Signal Line.

macd_plot <- data2 |>
    ggplot2$ggplot(ggplot2$aes(x = datetime)) +
    dmplot$stat_macd(data = data2,
        ggplot2$aes(macd = macd, macd_signal = macd_signal, macd_diff = macd_diff)
    ) +
    dmplot$theme_dereck_dark() +
    ggplot2$scale_x_datetime(date_breaks = "1 day", date_labels = "%b %d") +
    ggplot2$labs(
        title = paste(ticker, "- MACD"),
        x = "Date",
        y = "MACD Value"
    ) +
    ggplot2$theme(axis.text.x = ggplot2$element_text(angle = 45, hjust = 1))

print(macd_plot)

5. Relative Strength Index (RSI)

RSI is a momentum oscillator that measures the speed and change of price movements.

Mathematics:

\[ RSI = 100 - (100 / (1 + RS)) \]

where RS = Average Gain / Average Loss

\[ Average Gain = [(previous avg. gain) x 13 + current gain] / 14 \] \[ Average Loss = [(previous avg. loss) x 13 + current loss] / 14 \]

rsi <- function(x, n = 14) {
    as.list(as.data.frame(TTR::RSI(x, n = n)))
}

data2 <- dt$copy(data)

data2[, rsi := rsi(close, n = 14)[[1]]]

head(data2)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 2 variable(s) not shown: [turnover <num>, rsi <num>]

The RSI provides a visual representation of the strength of a security’s price movement. It is often used to identify overbought or oversold conditions.

rsi_plot <- na.omit(data2) |>
    ggplot2$ggplot(ggplot2$aes(x = datetime)) +
    ggplot2$geom_line(ggplot2$aes(y = rsi, colour = "RSI")) +
    ggplot2$geom_hline(
        yintercept = c(30, 70),
        linetype = "dashed",
        colour = "yellow"
    ) +
    ggplot2$scale_x_datetime(date_breaks = "1 day", date_labels = "%b %d") +
    ggplot2$scale_y_continuous(limits = c(0, 100)) +
    ggplot2$scale_color_manual(values = c("RSI" = "cyan")) +
    ggplot2$labs(
        title = paste(ticker, "- RSI"),
        x = "Date",
        y = "RSI Value"
    ) +
    dmplot$theme_dereck_dark() +
    ggplot2$theme(
        axis.text.x = ggplot2$element_text(angle = 45, hjust = 1),
        legend.position = "none"
    )

print(rsi_plot)

6. Rate of Change (ROC) / Momentum

The Rate of Change (ROC) indicator measures the percentage change in price between the current price and the price n periods ago.

Mathematics:

\[ ROC = \frac{Close - Close_{n}}{Close_{n}} \]

where n is the number of periods.

This is often used as a momentum indicator to identify overbought or oversold conditions.

Notice how we execute a second calculation to normalise the momentum values between -1 and 1.

\[ Momentum = \frac{ROC}{max(|ROC|)} \]

data2 <- dt$copy(data)

data2[, mom := TTR::ROC(close, n = 2L)]
data2[, mom := mom / max(abs(mom), na.rm = TRUE)]

head(data2)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 2 variable(s) not shown: [turnover <num>, mom <num>]

The Momentum indicator is a simple way to visualise the rate of change in price over a specified number of periods.

mom <- data2 |>
    ggplot2$ggplot(ggplot2$aes(
        x = datetime,
        y = mom,
        group = symbol
    )) +
    ## ------------------------------------
    # momentum
    ggplot2$geom_line(
        colour = "yellow",
        linewidth = 1.25,
        alpha = 0.5,
        na.rm = TRUE
    ) +
    ## ------------------------------------
    # zero line
    ggplot2$geom_hline(
        yintercept = 0, colour = "grey", size = 1, linetype = "dashed"
    ) +
    ggplot2$scale_x_datetime(
        date_breaks = "1 day", date_minor_breaks = "1 hour", date_labels = "%d %b"
    ) +
    ggplot2$labs(
        x = ggplot2::element_blank(),
        y = "Momentum"
    ) +
    dmplot$theme_dereck_dark() +
    ggplot2$theme(
        axis.text.x = ggplot2$element_text(angle = 90),
        panel.grid.minor = ggplot2$element_blank()
    )

print(mom)

7. Stochastic Oscillator

The Stochastic Oscillator is a momentum indicator that shows the location of the close relative to the high-low range over a set number of periods.

Mathematics:

\[ %K = (Current Close - Lowest Low)/(Highest High - Lowest Low) * 100 \]

\[ %D = 3-day SMA of %K \]

stoch <- function(high, low, close, n = 14, k = 3, d = 3) {
    as.list(as.data.frame(TTR::stoch(HLC = data.frame(high, low, close), nFastK = n, nFastD = k, nSlowD = d)))
}

data2 <- dt$copy(data)

data2[,
    c("fastK", "fastD", "slowD") := stoch(high, low, close, n = 14, k = 3, d = 3)
]

# similarly to the momentum indicator, we normalise the values between 0 and 100
data2[, fastK := fastK / max(abs(fastK), na.rm = TRUE) * 100]
data2[, fastD := fastD / max(abs(fastD), na.rm = TRUE) * 100]
data2[, slowD := slowD / max(abs(slowD), na.rm = TRUE) * 100]

head(data2)
#>      symbol            datetime    open    high     low   close   volume
#>      <char>              <POSc>   <num>   <num>   <num>   <num>    <num>
#> 1: BTC/USDT 2024-07-06 05:00:00 56057.9 56485.8 56025.2 56363.1 79.48139
#> 2: BTC/USDT 2024-07-06 06:00:00 56363.1 56573.3 56346.6 56413.8 41.94569
#> 3: BTC/USDT 2024-07-06 07:00:00 56413.7 56672.4 56402.5 56602.2 98.02022
#> 4: BTC/USDT 2024-07-06 08:00:00 56602.2 56655.3 56508.8 56555.8 49.06419
#> 5: BTC/USDT 2024-07-06 09:00:00 56555.9 56767.0 56441.6 56759.9 42.89421
#> 6: BTC/USDT 2024-07-06 10:00:00 56757.4 56887.1 56645.3 56786.6 45.64148
#> 4 variable(s) not shown: [turnover <num>, fastK <num>, fastD <num>, slowD <num>]

The Stochastic Oscillator is used to identify overbought or oversold conditions. When the %K line crosses above the %D line, it is considered a buy signal. When the %K line crosses below the %D line, it is considered a sell signal.

  • Dotted yellow lines represent the overbought (80) and oversold (20) levels.
  • Purple line represents the Fast %K line; this represents the current close relative to the high-low range over the last 14 periods.
  • Yellow line represents the Slow %D line; this is a 3-day SMA of the Fast %K line.

If the Fast %K line crosses above the Slow %D line, it is considered a buy signal. If the Fast %K line crosses below the Slow %D line, it is considered a sell signal.

stoch_plot <- na.omit(data2) |>
    ggplot2$ggplot(ggplot2$aes(x = datetime)) +
    ggplot2$geom_line(ggplot2$aes(y = fastK, colour = "Fast %K")) +
    ggplot2$geom_line(ggplot2$aes(y = slowD, colour = "Slow %D")) +
    ggplot2$geom_hline(
        yintercept = c(20, 80),
        linetype = "dashed",
        colour = "yellow"
    ) +
    ggplot2$scale_x_datetime(date_breaks = "1 day", date_labels = "%b %d") +
    ggplot2$scale_y_continuous(limits = c(0, 100)) +
    ggplot2$scale_color_manual(values = c("Fast %K" = "magenta", "Slow %D" = "yellow")) +
    ggplot2$labs(
        title = paste(ticker, "- Stochastic Oscillator"),
        x = "Date",
        y = "Value"
    ) +
    dmplot$theme_dereck_dark() +
    ggplot2$theme(axis.text.x = ggplot2$element_text(angle = 45, hjust = 1))

print(stoch_plot)

Pulling it all together

Now that we have built the individual layers, we can combine them into a single plot to visualise all the indicators together.

For this we use the gridExtra package to arrange the plots in a grid layout.

box::use(gridExtra)

Candlestick Chart + RSI + Volume

Now we will have some fun and combine the candlestick chart, RSI, and volume plots into a single layout.

candle_plot_minus_x_axis <- candle_plot +
    ema_layer +
    bb_layer +
    ggplot2$theme(
        axis.text.x = ggplot2$element_blank(),
        axis.title.x = ggplot2$element_blank()
    ) +
    ggplot2$labs(
        title = paste(ticker, "- Candlestick, EMA, Bollinger Bands, RSI, MACD, Volume"),
        y = "Price (USD)"
    )

rsi_plot_minus_x_axis <- rsi_plot +
    ggplot2$theme(
        axis.text.x = ggplot2$element_blank(),
        axis.title.x = ggplot2$element_blank()
    ) +
    ggplot2$labs(title = NULL, y = "RSI")

macd_plot_minus_x_axis <- macd_plot +
    ggplot2$theme(
        axis.text.x = ggplot2$element_blank(),
        axis.title.x = ggplot2$element_blank()
    ) +
    ggplot2$labs(title = NULL, y = "MACD")

gridExtra$grid.arrange(
    candle_plot_minus_x_axis,
    rsi_plot_minus_x_axis,
    macd_plot_minus_x_axis,
    volume_plot,
    ncol = 1,
    heights = c(3, 1, 1, 1)
)

Challenge: can you adjust the left padding on the plots so the y-axis labels all align?

Conclusion

This vignette has demonstrated how to calculate and visualise various financial indicators using the dmplot package. We’ve covered the mathematics behind each indicator and provided R functions to calculate them. By combining these indicators with the visualisation capabilities of dmplot, you can create comprehensive and insightful financial charts.

Remember that while these indicators can be powerful tools for technical analysis, they should be used in conjunction with other forms of analysis and not relied upon exclusively for making investment decisions.

For more advanced usage and customisation options, refer to the individual function documentation in the dmplot package and explore combining multiple indicators to create more complex trading strategies.