This vignette illustrates how to estimate bid-ask spreads from open, high, low, and close prices. Let’s start by loading the package:
The package offers two ways to estimate bid-ask spreads:
edge(): designed for tidy data.spread(): designed for xts objects.The function edge() implements the efficient estimator
described in Ardia,
Guidotti, & Kroencke (2021). Open, high, low, and close prices
are to be passed as separate vectors.
The function spread() requires an xts
object containing columns named Open, High,
Low, Close and it provides additional
functionalities, such as additional estimators and rolling
estimates.
An output value of 0.01 corresponds to a spread estimate of 1%.
Examples are provided below.
The function edge() can be easily used with tidy data
and the dplyr grammar. In the following example, we
estimate bid-ask spreads for cryptocurrencies.
Download daily prices for Bitcoin and Ethereum using the crypto2 package:
library(dplyr)
library(crypto2)
df <- crypto_list(only_active=TRUE) %>%
  filter(symbol %in% c("BTC", "ETH")) %>%
  crypto_history(start_date = "20200101", end_date = "20221231")
#> ❯ Scraping historical crypto data
#> ❯ Processing historical crypto datahead(df)
#> # A tibble: 6 × 16
#>   timestamp              id slug    name  symbol ref_cur  open  high   low close
#>   <dttm>              <int> <chr>   <chr> <chr>  <chr>   <dbl> <dbl> <dbl> <dbl>
#> 1 2020-01-01 23:59:59     1 bitcoin Bitc… BTC    USD     7195. 7254. 7175. 7200.
#> 2 2020-01-02 23:59:59     1 bitcoin Bitc… BTC    USD     7203. 7212. 6935. 6985.
#> 3 2020-01-03 23:59:59     1 bitcoin Bitc… BTC    USD     6984. 7414. 6915. 7345.
#> 4 2020-01-04 23:59:59     1 bitcoin Bitc… BTC    USD     7345. 7427. 7310. 7411.
#> 5 2020-01-05 23:59:59     1 bitcoin Bitc… BTC    USD     7410. 7544. 7401. 7411.
#> 6 2020-01-06 23:59:59     1 bitcoin Bitc… BTC    USD     7410. 7782. 7409. 7769.
#> # ℹ 6 more variables: volume <dbl>, market_cap <dbl>, time_open <dttm>,
#> #   time_close <dttm>, time_high <dttm>, time_low <dttm>Estimate the spread for each coin in each year:
df %>%
  mutate(yyyy = format(timestamp, "%Y")) %>%
  group_by(symbol, yyyy) %>%
  arrange(timestamp) %>%
  summarise(EDGE = edge(open, high, low, close))
#> # A tibble: 6 × 3
#> # Groups:   symbol [2]
#>   symbol yyyy      EDGE
#>   <chr>  <chr>    <dbl>
#> 1 BTC    2020  0.00319 
#> 2 BTC    2021  0.00376 
#> 3 BTC    2022  0.000200
#> 4 ETH    2020  0.00223 
#> 5 ETH    2021  0.00628 
#> 6 ETH    2022  0.00262xts objectsThe function spread() provides additional
functionalities for xts objects. In the
following example, we estimate bid-ask spreads for equities.
Download daily data for Microsoft (MSFT) using the quantmod package:
library(quantmod)
x <- getSymbols("MSFT", auto.assign = FALSE, start = "2019-01-01", end = "2022-12-31")
head(x)
#>            MSFT.Open MSFT.High MSFT.Low MSFT.Close MSFT.Volume MSFT.Adjusted
#> 2007-01-03     29.91     30.25    29.40      29.86    76935100      21.43699
#> 2007-01-04     29.70     29.97    29.44      29.81    45774500      21.40110
#> 2007-01-05     29.63     29.75    29.45      29.64    44607200      21.27906
#> 2007-01-08     29.65     30.10    29.53      29.93    50220200      21.48725
#> 2007-01-09     30.00     30.18    29.73      29.96    44636600      21.50879
#> 2007-01-10     29.80     29.89    29.43      29.66    55017400      21.29341This is an xts object:
So we can estimate the spread with:
By default, the call above is equivalent to:
But spread() also provides additional functionalities.
For instance, estimate the spread for each month and plot the
estimates:
Or estimate the spread using a rolling window of 21 obervations:
To illustrate higher-frequency estimates, we are going to download intraday data from Alpha Vantage. You must register with Alpha Vantage in order to download their data, but the one-time registration is fast and free. Register at https://www.alphavantage.co/ to receive your key. You can set the API key globally as follows:
Download minute data for Microsoft:
x <- getSymbols(
  Symbols = "MSFT", 
  auto.assign = FALSE, 
  src = "av", 
  periodicity = "intraday", 
  interval = "1min", 
  output.size = "full")head(x)
#>                     MSFT.Open MSFT.High MSFT.Low MSFT.Close MSFT.Volume
#> 2023-08-17 04:00:00    319.20    322.00   319.20     320.39         992
#> 2023-08-17 04:01:00    320.03    320.18   320.00     320.18         914
#> 2023-08-17 04:02:00    320.38    320.38   320.35     320.35         170
#> 2023-08-17 04:03:00    320.35    320.35   320.06     320.34          96
#> 2023-08-17 04:04:00    320.34    320.34   320.34     320.34          17
#> 2023-08-17 04:05:00    320.34    320.34   320.29     320.30          11Estimate the spread for each day and plot the estimates:
If you find this package useful, please star the repo!
The repository also contains implementations for Python, C++, MATLAB, and more.
Ardia, David and Guidotti, Emanuele and Kroencke, Tim Alexander, “Efficient Estimation of Bid-Ask Spreads from Open, High, Low, and Close Prices”. Available at SSRN: https://www.ssrn.com/abstract=3892335
A BibTex entry for LaTeX users is: