AbnormalReturns API
This package reexports StatsModels.jl and BusinessDays.jl. See those packages and their respective documentation for methods that they export.
Notable methods from StatsModels.jl:
@formula
Notable methods from BusinessDays.jl:
advancebdays
bdayscount
tobday
Setting Up Data
AbnormalReturns.MarketData
— Typefunction MarketData(
df_market,
df_firms;
date_col_market=:date,
date_col_firms=:date,
id_col=:permno,
add_intercept_col=true,
valuecols_market=nothing,
valuecols_firms=nothing
)
Arguments
df_market
: A Tables.jl compatible source that stores market data, indexed by date. The dates must be a unique set. The column name for the date column is specified by the keyword argument "datecolmarket"df_firms
: A Tables.jl compatible source that stores firm data. Each firm must have a unique set of dates. The column name for the date column is specified by the keyword argument "datecolfirms" and the firm ID column is specified by the keyword argument "id_col"valuecols_market=nothing
: If left as nothing, all other columns indf_market
are used as the value columns. These are the columns that are stored in the resulting dataset. Otherwise a vector of Symbol or String specifying column names.valuecols_firms=nothing
: Same as aboveid_col=:permno
: The column corresponding to the set of firm IDs indf_firms
add_intercept_col=true
: Whether to add a column to the data for an intercept (which is always equal to 1)
MarketData is the main data storage structure. Data is stored for each firm in a Dict, where the data itself is a NamedTuple (names corresponding to column names, such as "ret"), and the keys for the Dict corresponding to firm IDs. The MarketData struct also stores overall market data and a calendar of dates.
Any firm data must have a corresponding market data date, so there cannot be a firm return if there is not a market return on that date.
Example
df_firm = CSV.File(joinpath(data_dir, "daily_ret.csv"))
df_mkt = CSV.File(joinpath(data_dir, "mkt_ret.csv"))
df_mkt[!, :mkt] = df_mkt.mktrf .+ df_mkt.rf
mkt_data = MarketData(
df_mkt,
df_firm
)
AbnormalReturns.all_unique_obs
— FunctionChecks whether each firmid-date pair is unique, assumes that vectors are sorted by firmid then date
Returns true if there is at least one firm_id-date pair repeated, false if all are unique
Regression Related Methods
AbnormalReturns.quick_reg
— Functionquick_reg(
data::FixedTable,
f::FormulaTerm;
minobs::Real=0.8,
save_residuals::Bool=false
)
quick_reg(
data::IterateFixedTable,
f::FormulaTerm;
minobs::Real=0.8,
save_residuals::Bool=false
)
Calculates a linear regression for the supplied data based on the formula (formula from StatsModels.jl). Unless the formula explicitly excludes the intercept (i.e., @formula(y ~ 0 + x)
), an intercept is added.
If data
is of the type IterateFixedTable
, then the function uses the maximum number of threads on each FixedTable
in an optimized way and returns a Vector{BasicReg}
.
Arguments
minobs::Real
: The minimum number of observations to return a completed regression. If less than 1, the value is used as a percentage relative to the total number of business days in the time period. Therefore, the default of 0.8 corresponds to at least 80% of the business days over the time period have values.save_residuals::Bool=false
: Whether to save the residuals intoBasicReg
, This can have significant performance implications.
AbnormalReturns.BasicReg
— Typefunction BasicReg(
resp::AbstractVector,
pred::AbstractMatrix,
yname::String,
xnames::SVector{N, String},
f::FormulaTerm{L,R};
save_residuals::Bool=false,
minobs=1
)::BasicReg{L,R} where {L,R}
Arguments
- resp::AbstractVector{Float64}: The "Y" or response in a linear regression
- pred::AbstractMatrix{Float64}: The "X" matrix in a linear regression
- yname::String: The name of the response variable
- xnames::SVector{N, String}: The names of the prediction variables
- f::FormulaTerm{L,R}: A StatsModels.jl formula, saved in the resulting struct
- save_residuals::Bool=false: Whether or not to save the vector of residuals from the regression. Note for large numbers of regressions this can significantly slow down the speed
- minobs::Int=1: The minimum length of the response vector for the regression to run. The regression will also not run if the length of the response vector is less than or equal to the number of columns in the prediction matrix.
BasicReg is an intentionally simplistic linear regression. It also attempts to produce a minimum number of allocations if views of vectors are passed.
AbnormalReturns.alpha
— Functionalpha(rr::RegressionModel, coefname::String...="intercept")
"alpha" in respect to the the CAPM model, i.e., the intercept in the model. This is the alpha from the estimation period.
This function finds the position of the coefficient name provided, defaults to "intercept". If the coefname is not in the regression, then this function returns an error.
AbnormalReturns.beta
— Functionbeta(rr::RegressionModel, coefname::String...=["mkt", "mktrf", "vwretd", "ewretd"])
"beta" in respect to the CAPM model, i.e., the coefficient on the market return minus the risk free rate. This is the beta from the estimation period.
This function finds the position of the coefficient name provided, defaults to several common market returns. If the coefname is not in the regression, then this function returns an error.
Statistics.var
— Functionvar[std](rr::Union{AbstractVector{<:RegressionModel}, RegressionModel})
var[std](data::Union{IterateFixedTable, FixedTable}; minobs=0.8)
If a regression model is passed, then this calculates the variance (standard deviation) based on the residual sum of squares divided by the degrees of freedom. A vector of RegressionModel will return the same length of vector results.
If a FixedTable is passed (or an IterateFixedTable), and that contains only one column, then the variance (standard deviation) is calculated for that column. If it has two columns, then the calculation is based on the difference between the columns.
Statistics.std
— FunctionSee var
.
Calculation Functions
AbnormalReturns.bhar
— Functionbhar(
data::FixedTable{T, 2};
minobs=0.8
) where {T}
bhar(
data::FixedTable,
rr::RegressionModel;
minobs=0.8
)
bhar(
data::IterateFixedTable{T, 2};
minobs=0.8
) where {T, MNames, FNames}
bhar(
data::IterateFixedTable,
rrs::AbstractVector{<:BasicReg};
minobs=0.8
)
Calculates the difference between buy and hold returns (also referred to as geometric returns) for a firm and a benchmark. If a regression is passed, then the benchmark is based on the coefficients from that regression and the performance of the benchmarks in the regression. These are sometimes called Fama-French abnormal returns. If no regression is passed, abnormal returns are calculated as the difference between the first and second columns in the FixedTable (second column is typically the benchmark such as the S&P 500 or a value weighted return of all firms).
Similar to constructing the regression, passing an IterateFixedTable
will return a Vector and uses a more optimized method.
AbnormalReturns.car
— Functioncar(
data::FixedTable{T, 2};
minobs=0.8
) where {T}
car(
data::FixedTable,
rr::RegressionModel;
minobs=0.8
)
car(
data::IterateFixedTable{T, 2};
minobs=0.8
) where {T, MNames, FNames}
car(
data::IterateFixedTable,
rrs::AbstractVector{<:BasicReg};
minobs=0.8
)
Calculates the cumulative returns of a firm over a benchmark (through addition of each return). If a regression is passed, then the benchmark is based on the coefficients from that regression and the performance of the benchmarks in the regression. These are sometimes called Fama-French abnormal returns. If no regression is passed, abnormal returns are calculated as the difference between the first and second columns in the FixedTable (second column is typically the benchmark such as the S&P 500 or a value weighted return of all firms).
Similar to constructing the regression, passing an IterateFixedTable
will return a Vector and uses a more optimized method.
AbnormalReturns.bh_return
— FunctionCalculates the buy and hold returns (also called geometric return).
These functions treat missing returns in the period implicitly as a zero return.