business-science / tidyquant

Bringing financial analysis to the tidyverse
https://business-science.github.io/tidyquant/
Other
852 stars 175 forks source link

`tq_portfolio()` is too restrictive about weights #175

Closed echasnovski closed 1 year ago

echasnovski commented 4 years ago

While using tq_portfolio(), warning "Sum of weights must be 1" can be shown in situations where user really can't do much about improving weights. The reason is that their sum isn't exactly 1 due to floating point number representation. Here is a reprex:

library(tibble)
suppressPackageStartupMessages(library(tidyquant))

returns_df <- tibble(
  symbol = rep(c("A", "B", "C"), each = 3),
  date = rep(ISOdatetime(2020, 1, 1:3, 0, 0, 0, tz = "UTC"), times = 3),
  Ra = rep(c(1, 1, -1), times = 3) / 100
)

# Set certain seed which was picked by hand for warning to occur
set.seed(187)
weights <- runif(3)
weights <- weights / sum(weights)

tq_portfolio(
  data = returns_df,
  assets_col = symbol,
  returns_col = Ra,
  weights = weights
)
#> Warning in check_weights(weights, assets_col, map, x): Sum of weights must be 1.
#> # A tibble: 3 x 2
#>   date                portfolio.returns
#>   <dttm>                          <dbl>
#> 1 2020-01-01 00:00:00              0.01
#> 2 2020-01-02 00:00:00              0.01
#> 3 2020-01-03 00:00:00             -0.01

sum(weights) - 1
#> [1] -1.110223e-16

Created on 2020-07-03 by the reprex package (v0.3.0)

This happens because internal check_weights() functions uses sum(weights) == 1 condition to decide when warning should be shown. Usually it is a better idea to check equality with some threshold. For example, using dplyr::near(sum(weights), 1).