Applies sample construction filters to a data frame before portfolio sorting. Filters are applied in a fixed order: financials exclusion, utilities exclusion, minimum stock price, minimum size quantile, minimum listing age, positive book equity, and positive earnings. An informational message is emitted for each filter that actually removes at least one observation.
Usage
filter_sorting_data(
data,
filter_options = NULL,
data_options = NULL,
rebalancing_month = NULL,
quiet = FALSE
)Arguments
- data
A data frame containing the stock-level panel data to be filtered.
- filter_options
A list of class
tidyfinance_filter_optionscreated byfilter_options(). IfNULL(the default), the defaults fromfilter_options()are used (i.e., no filters are applied). The arguments accepted byfilter_options()includeexclude_financialsA logical indicating whether to exclude financial firms (SIC codes 6000–6799). Defaults toFALSE.exclude_utilitiesA logical indicating whether to exclude utility firms (SIC codes 4900–4999). Defaults toFALSE.min_stock_priceA single positive numeric specifying the minimum stock price required to include an observation.NULL(the default) applies no price filter.min_size_quantileA single numeric strictly between 0 and 1 specifying the minimum cross-sectional size quantile (based on lagged market cap) required to include an observation.NULL(the default) applies no size quantile filter. The cutoff is computed from NYSE stocks only; theexchangecolumn (mapped viadata_options()) must be present in the data or an error is raised.min_listing_ageA single non-negative integer or numeric specifying the minimum number of months a stock must have been listed in CRSP.NULL(the default) applies no listing age filter.exclude_negative_book_equityA logical indicating whether to exclude observations with non-positive book equity. Defaults toFALSE.exclude_negative_earningsA logical indicating whether to exclude observations with non-positive earnings. Defaults toFALSE.timingEither"formation"(the default) to apply the screens only in the formation month when portfolios are rebalanced once a year, or"every_period"to apply them in every month, which can introduce look-ahead bias.
- data_options
A list of class
tidyfinance_data_options(created viadata_options()) specifying column name mappings. Thesiccdelement is used to specify the SIC code column,priceis used to specify the price column of themin_stock_pricescreen,mktcap_lagis used to specify the market capitalization column,dateis used to specify the date column,listing_ageis used to specify the listing age column,beis used to specify the book equity column, andearningsis used to specify the earnings column. Usesdata_options()default ifNULL:"siccd" = "siccd","price" = "prc_lag","exchange" = "exchange""mktcap_lag" = "mktcap_lag","date" = "date","listing_age" = "listing_age","be" = "be", and"earnings" = "ib". Withrebalancing_month, theidelement (default"permno") is used to keep a stock across its holding period.- rebalancing_month
An optional integer between 1 and 12 specifying the month in which portfolios are formed when they are rebalanced once a year (see
compute_portfolio_returns()).NULL(the default) means monthly rebalancing. Together with thetimingelement offilter_options, it determines when the screens apply; see Details.- quiet
A logical indicating whether informational messages should be suppressed. Defaults to
FALSE.
Details
Without rebalancing_month, every month is a formation month and each row
is screened on its own values. The screens are then free of look-ahead bias
only if the screened columns are known at the start of the month: the
default price column prc_lag and mktcap_lag are lagged by one month,
and accounting variables such as book equity and earnings should be lagged
as well (e.g., with join_lagged_values()).
With rebalancing_month, portfolios are formed once a year and held for
twelve months. By default (filter_options(timing = "formation")), each
screen is evaluated in the formation month only, and a stock that passes
all screens keeps all its rows until the next formation month, even if it
fails a screen in a holding month. Rows of stocks that fail a screen at
formation, and rows before the first formation month, are removed. With
timing = "every_period", the screens are evaluated in every month
(ex-post) and a warning is issued, because dropping holding-month returns
based on information from those months can bias factor returns.
The threshold and sign screens (min_stock_price, min_size_quantile,
min_listing_age, exclude_negative_book_equity,
exclude_negative_earnings) drop an observation when the screened value is
missing; the industry exclusions (exclude_financials, exclude_utilities)
keep an observation whose SIC code is missing.
Examples
data <- data.frame(
permno = 1:5,
date = as.Date("2020-01-01"),
siccd = c(6100, 2000, 4950, 3000, 6500),
prc_lag = c(5, 0.5, 15, 20, 10)
)
data |>
filter_sorting_data(
filter_options = filter_options(
exclude_financials = TRUE,
min_stock_price = 1
)
)
#> Filter 'exclude_financials': removed 2 observations.
#> Filter 'min_stock_price': removed 1 observation.
#> permno date siccd prc_lag
#> 1 3 2020-01-01 4950 15
#> 2 4 2020-01-01 3000 20
# Annual rebalancing in July: the price screen is evaluated in July only,
# so stock 1 is kept in August although its price falls below 1
data_annual <- data.frame(
permno = rep(1:2, each = 2),
date = as.Date(rep(c("2020-07-01", "2020-08-01"), 2)),
prc_lag = c(2, 0.5, 0.5, 2)
)
data_annual |>
filter_sorting_data(
filter_options = filter_options(min_stock_price = 1),
rebalancing_month = 7
)
#> Filter 'min_stock_price': removed 1 observation.
#> Screens applied in formation month 7: removed 1 holding-month observation of
#> stocks that failed a screen at formation or precede the first formation month.
#> permno date prc_lag
#> 1 1 2020-07-01 2.0
#> 2 1 2020-08-01 0.5