financialkit.asset_pricing#

Williams’s dividend discount model and Gordon growth (through financialkit.time_value.perpetuity_present_value()), Modigliani-Miller and the weighted average cost of capital, and Shiller’s variance bound; Sharpe’s CAPM with the market as the tangency portfolio (financialkit.risk.safety_first_portfolio()), Jensen’s alpha, Black’s zero-beta CAPM and the Gibbons-Ross-Shanken test; time-series factor regressions (through financialkit.time_series.ols()), Fama-MacBeth premia, Ross’s APT and its arbitrage portfolios, and the characteristic sorts behind the Fama-French and Carhart factors; Lucas’s tree, Breeden’s consumption CAPM and the Mehra-Prescott economy; Harrison-Kreps state prices with scipy.optimize.linprog and the Hansen-Jagannathan bound.

financialkit.asset_pricing: valuation, the CAPM, factor models, consumption-based pricing and the SDF.

Williams’s dividend discount model and Gordon growth (through financialkit.time_value.perpetuity_present_value()), Modigliani-Miller and the cost of capital, Shiller’s variance bound; Sharpe’s CAPM with the market as the tangency portfolio, Jensen’s alpha, Black’s zero-beta CAPM and the Gibbons-Ross-Shanken test; time-series factor regressions (through financialkit.time_series.ols()), Fama-MacBeth premia, Ross’s APT and arbitrage portfolios, and the characteristic sorts behind Fama-French and Carhart factors; Lucas’s tree, Breeden’s consumption CAPM and Mehra-Prescott’s equity premium puzzle; Harrison-Kreps state prices and the Hansen-Jagannathan bound. Return panels have shape (n_periods, n_assets), and the consumption-based models use gross returns.

class financialkit.asset_pricing.CAPMEquilibrium(market_weights, betas, expected_returns, risk_free, market_return, market_vol)[source]#

Bases: object

The CAPM equilibrium of a mean-variance market with a riskless asset.

Parameters:
betas: ndarray#

Beta of each asset on the market portfolio.

Type:

ndarray, shape (d,)

expected_returns: ndarray#

Expected returns of the assets.

Type:

ndarray, shape (d,)

property market_premium: float#

Expected market return minus the riskless rate.

Type:

float

market_return: float#

Expected return of the market portfolio.

market_vol: float#

Volatility of the market portfolio.

market_weights: ndarray#

Tangency (market) portfolio, summing to one.

Type:

ndarray, shape (d,)

risk_free: float#

Riskless rate.

property sml_errors: ndarray#

Distance of each asset from the security market line (zero in equilibrium).

Type:

ndarray

class financialkit.asset_pricing.ConsumptionEconomy(beta, gamma)[source]#

Bases: ABC

An endowment economy with a CRRA representative agent who eats the dividend of a Lucas tree.

Parameters:
  • beta (float) – Time-discount factor in (0, 1].

  • gamma (float) – Relative risk aversion, positive.

abstractmethod moments()[source]#

Unconditional moments of the riskless rate, the equity return and the SDF.

Return type:

ConsumptionMoments

abstractmethod simulate(n_periods, rng=None)[source]#

Simulate consumption growth with the matching SDF and returns.

Return type:

EconomyPath

Parameters:
class financialkit.asset_pricing.ConsumptionMoments(price_dividend, risk_free, equity_return, equity_vol, sdf_mean, sdf_vol)[source]#

Bases: object

Unconditional moments of a consumption-based economy; all returns are gross.

Parameters:
property equity_premium: float#

Expected equity return minus the riskless return.

Type:

float

equity_return: float#

Expected gross return of the consumption claim.

equity_vol: float#

Standard deviation of the equity return.

price_dividend: float#

Average price-dividend ratio of the consumption claim.

risk_free: float#

Average gross riskless return.

sdf_mean: float#

\(E[m]\).

sdf_vol: float#

\(\sigma(m)\).

property sharpe_ratio: float#

Equity premium over equity volatility.

Type:

float

class financialkit.asset_pricing.EconomyPath(growth, sdf, equity_return, risk_free)[source]#

Bases: object

A simulated path of a consumption economy; returns are gross and dated at the period’s end.

Parameters:
equity_return: ndarray#

Gross return of the consumption claim.

Type:

ndarray, shape (n,)

growth: ndarray#

Gross consumption (and dividend) growth.

Type:

ndarray, shape (n,)

risk_free: ndarray#

Gross riskless return, known at the start of the period.

Type:

ndarray, shape (n,)

sdf: ndarray#

Stochastic discount factor \(\beta G^{-\gamma}\).

Type:

ndarray, shape (n,)

class financialkit.asset_pricing.ExcessVolatilityResult(price, rational_price, std_price, std_rational)[source]#

Bases: object

Shiller’s variance-bound comparison of actual and ex-post rational prices.

Parameters:
price: ndarray#

Actual price.

Type:

ndarray, shape (T,)

property ratio: float#

std_price / std_rational; above one violates the bound.

Type:

float

rational_price: ndarray#

Ex-post rational price \(p^*\), the discounted realized dividends.

Type:

ndarray, shape (T,)

std_price: float#

Standard deviation of the actual price.

std_rational: float#

Standard deviation of \(p^*\).

property violated: bool#

Whether the price is more volatile than the efficient-markets bound allows.

Type:

bool

class financialkit.asset_pricing.FactorPanel(excess_returns, factors, betas, alphas)[source]#

Bases: object

Excess returns generated by \(r^e_t = \alpha + B f_t + \varepsilon_t\).

Parameters:
alphas: ndarray#

True pricing errors.

Type:

ndarray, shape (n,)

betas: ndarray#

True loadings.

Type:

ndarray, shape (n, k)

excess_returns: ndarray#

ndarray, shape (T, n).

factors: ndarray#

Factor excess returns.

Type:

ndarray, shape (T, k)

class financialkit.asset_pricing.FactorRegressionResult(alphas, betas, alpha_se, r_squared, residuals)[source]#

Bases: object

Time-series regressions \(r^e_{it} = \alpha_i + \beta_i' f_t + \varepsilon_{it}\), one per asset.

Parameters:
alpha_se: ndarray#

Classical standard errors of the intercepts.

Type:

ndarray, shape (n,)

property alpha_t: ndarray#

t-statistics of the intercepts.

Type:

ndarray

alphas: ndarray#

Intercepts, the pricing errors.

Type:

ndarray, shape (n,)

betas: ndarray#

Factor loadings.

Type:

ndarray, shape (n, k)

r_squared: ndarray#

Explained share of each asset’s variance.

Type:

ndarray, shape (n,)

residuals: ndarray#

Regression residuals.

Type:

ndarray, shape (T, n)

class financialkit.asset_pricing.FamaMacBethResult(gammas, premia, std_errors, betas)[source]#

Bases: object

Fama-MacBeth cross-sectional regressions \(r^e_{it} = \gamma_{0t} + \gamma_t' \beta_i + u_{it}\).

Parameters:
betas: ndarray#

Loadings used as regressors in the second pass.

Type:

ndarray, shape (n, k)

gammas: ndarray#

Each period’s intercept and slopes.

Type:

ndarray, shape (T, k + 1)

premia: ndarray#

Time averages of the gammas: the zero-beta excess return, then the factor premia.

Type:

ndarray, shape (k + 1,)

std_errors: ndarray#

Standard errors from the time series of gammas, std / sqrt(T).

Type:

ndarray, shape (k + 1,)

property t_values: ndarray#

Premia divided by their standard errors.

Type:

ndarray

class financialkit.asset_pricing.FiniteStateMarket(payoffs, prices, probabilities=None)[source]#

Bases: object

A one-period market with finitely many states, traded payoffs and their prices.

Parameters:
  • payoffs (ArrayLike) – Payoff of each of N securities in each of S states.

  • prices (ArrayLike) – Today’s prices.

  • probabilities (ArrayLike | None) – Physical state probabilities, needed only for the SDF; equal by default.

Examples

A bond paying 1 and a stock paying 2 or 0.5, priced 0.95 and 1:

>>> mkt = FiniteStateMarket([[1.0, 2.0], [1.0, 0.5]], [0.95, 1.0])
>>> mkt.state_prices().round(4).tolist(), mkt.is_complete, mkt.is_arbitrage_free()
([0.35, 0.6], True, True)
arbitrage_portfolio()[source]#

Holdings that cost nothing or less and pay something and never lose, if any exist.

Solves a linear program over holdings theta with payoffs X theta >= 0 and cost p @ theta <= 0, maximising the total payoff minus the cost within a unit box. Returns zeros when the market is arbitrage free.

Return type:

ndarray

Returns:

ndarray, shape (N,)

is_arbitrage_free(tol=1e-10)[source]#

Whether a strictly positive state-price vector exists (Harrison-Kreps).

Return type:

bool

Parameters:

tol (float)

property is_complete: bool#

Whether the payoffs span every state (rank S).

Type:

bool

price_bounds(claim)[source]#

Lowest and highest arbitrage-free price of a new payoff.

The extremes of \(q' x\) over nonnegative state prices that price the traded assets. The bounds coincide in a complete market.

Parameters:

claim (ArrayLike)

Return type:

tuple[float, float]

Returns:

tuple of float – (low, high).

risk_free_return()[source]#

Gross return of the riskless payoff, 1 / sum(q).

Return type:

float

risk_neutral_probabilities()[source]#

State prices normalised to sum to one.

Return type:

ndarray

sdf()[source]#

Stochastic discount factor in each state, \(m_s = q_s / \pi_s\).

Return type:

ndarray

state_prices()[source]#

A strictly positive state-price vector, unique when the market is complete.

Return type:

ndarray

Returns:

ndarray, shape (S,)

Raises:

ValueError – If the market admits an arbitrage.

class financialkit.asset_pricing.GRSResult(statistic, p_value, df1, df2, alphas)[source]#

Bases: object

Gibbons, Ross and Shanken’s joint F-test that every alpha is zero.

Parameters:
alphas: ndarray#

Estimated intercepts.

Type:

ndarray, shape (n,)

df1: int#

Numerator degrees of freedom, the number of test assets.

df2: int#

Denominator degrees of freedom, T - N - K.

p_value: float#

Exact p-value under normal errors.

reject(level=0.05)[source]#

Whether the model is rejected at significance level.

Return type:

bool

Parameters:

level (float)

statistic: float#

F-statistic.

class financialkit.asset_pricing.HJBound(sdf_means, sdf_stds)[source]#

Bases: object

Hansen and Jagannathan’s lower bound on the volatility of a stochastic discount factor.

Parameters:
admits(sdf_mean, sdf_std)[source]#

Whether an SDF with these moments lies inside the admissible region.

Return type:

bool

Parameters:
sdf_means: ndarray#

Candidate means \(E[m]\).

Type:

ndarray, shape (m,)

sdf_stds: ndarray#

Smallest \(\sigma(m)\) that prices the assets at each mean.

Type:

ndarray, shape (m,)

class financialkit.asset_pricing.LucasTree(beta, gamma, mu=0.018, sigma=0.036)[source]#

Bases: ConsumptionEconomy

Lucas’s tree with i.i.d. lognormal growth: every price in closed form.

Log consumption growth is \(g \sim N(\mu, \sigma^2)\), and the tree’s dividend is consumption. The price-dividend ratio is constant, \(P/D = \kappa / (1 - \kappa)\) with \(\kappa = \beta e^{(1-\gamma)\mu + (1-\gamma)^2\sigma^2/2}\), the riskless rate is \(\log R_f = -\log\beta + \gamma\mu - \gamma^2\sigma^2/2\), and the log equity premium is \(\log E[R_e] - \log R_f = \gamma\sigma^2\).

Parameters:
  • beta (float) – Time-discount factor.

  • gamma (float) – Relative risk aversion.

  • mu (float) – Mean of log consumption growth per period.

  • sigma (float) – Volatility of log consumption growth.

Examples

>>> m = LucasTree(beta=0.99, gamma=2.0, mu=0.02, sigma=0.036).moments()
>>> round(m.risk_free - 1, 4), round(m.equity_premium, 4)
(0.0486, 0.0027)
property kappa: float#

\(\beta E[G^{1-\gamma}]\), the discount applied to next period’s dividend.

Type:

float

moments()[source]#

Unconditional moments of the riskless rate, the equity return and the SDF.

Return type:

ConsumptionMoments

simulate(n_periods, rng=None)[source]#

Simulate consumption growth with the matching SDF and returns.

Return type:

EconomyPath

Parameters:
class financialkit.asset_pricing.MehraPrescott(beta, gamma, mu=0.018, delta=0.036, phi=0.43)[source]#

Bases: ConsumptionEconomy

Mehra and Prescott’s two-state Markov economy.

Gross consumption growth is \(\lambda_1 = 1 + \mu + \delta\) or \(\lambda_2 = 1 + \mu - \delta\), and the chain stays in its state with probability \(\phi\). The price-dividend ratios \(w_i\) solve \(w_i = \beta \sum_j \phi_{ij} \lambda_j^{1-\gamma}(w_j + 1)\), and the riskless return in state \(i\) is \(1 / (\beta \sum_j \phi_{ij} \lambda_j^{-\gamma})\). The defaults are their 1889-1978 calibration: mean growth 1.8%, standard deviation 3.6% and first-order autocorrelation -0.14.

Parameters:
  • beta (float)

  • gamma (float)

  • mu (float) – Mean consumption growth.

  • delta (float) – Half the gap between the two growth states (their standard deviation).

  • phi (float) – Probability of staying in the current state; the autocorrelation is 2 phi - 1.

Examples

>>> m = MehraPrescott(beta=0.99, gamma=10.0).moments()
>>> round(m.risk_free - 1, 3), round(m.equity_premium, 4)
(0.131, 0.0269)
property growth_autocorr: float#

First-order autocorrelation of consumption growth, 2 phi - 1.

Type:

float

moments()[source]#

Unconditional moments of the riskless rate, the equity return and the SDF.

Return type:

ConsumptionMoments

price_dividend#

Price-dividend ratio in each state.

Type:

ndarray, shape (2,)

risk_free#

Gross riskless return from each state.

Type:

ndarray, shape (2,)

simulate(n_periods, rng=None)[source]#

Simulate consumption growth with the matching SDF and returns.

Return type:

EconomyPath

Parameters:
class financialkit.asset_pricing.ZeroBetaResult(market_weights, zero_beta_weights, zero_beta_rate, betas, expected_returns, market_return)[source]#

Bases: object

Black’s zero-beta CAPM for an efficient market portfolio, without a riskless asset.

Parameters:
betas: ndarray#

Beta of each asset on the market portfolio.

Type:

ndarray, shape (d,)

expected_returns: ndarray#

Expected returns of the assets.

Type:

ndarray, shape (d,)

market_return: float#

Expected return of the market portfolio.

market_weights: ndarray#

Efficient (market) portfolio.

Type:

ndarray, shape (d,)

zero_beta_rate: float#

the security market line’s intercept.

Type:

Expected return of the zero-beta portfolio

zero_beta_weights: ndarray#

Minimum-variance portfolio uncorrelated with the market.

Type:

ndarray, shape (d,)

financialkit.asset_pricing.apt_arbitrage_portfolio(expected_returns, betas)[source]#

A zero-cost, zero-beta portfolio that earns any deviation from linear pricing.

The weights are the residuals of the cross-sectional regression of expected returns on a constant and the betas. Being orthogonal to the constant, they sum to zero (no cost); being orthogonal to every beta, they carry no factor risk; and their expected return is the sum of squared residuals, positive unless the APT holds exactly. With many assets the idiosyncratic risk of this portfolio diversifies away, which is Ross’s argument that the residuals must be small.

Parameters:
Return type:

ndarray

Returns:

ndarray, shape (n,) – Weights; their expected return is weights @ expected_returns.

Examples

>>> import numpy as np
>>> w = apt_arbitrage_portfolio([0.05, 0.08, 0.13], [0.0, 1.0, 2.0])
>>> bool(np.isclose(w.sum(), 0.0, atol=1e-9)), bool(np.isclose(w @ [0.0, 1.0, 2.0], 0.0, atol=1e-9))
(True, True)
>>> bool(np.isclose(w @ [0.05, 0.08, 0.13], 6.6667e-05, rtol=1e-4))
True
financialkit.asset_pricing.apt_expected_returns(betas, premia, risk_free=0.0)[source]#

Ross’s linear pricing relation \(E[r_i] = r_f + \beta_i' \lambda\).

Parameters:
Return type:

ndarray | float

Returns:

float or ndarray, shape (n,)

Examples

>>> round(apt_expected_returns([1.2, 0.5], [0.05, 0.02], 0.03), 12)
0.1
financialkit.asset_pricing.ar1_dividend_price(dividends, rate, rho, mean)[source]#

The rational price when dividends follow an AR(1) around a constant mean.

For \(D_{t+1} - \bar D = \rho (D_t - \bar D) + \varepsilon_{t+1}\), the expected present value of future dividends is \(\bar D / r + \rho (D_t - \bar D) / (1 + r - \rho)\).

Parameters:
  • dividends (ArrayLike) – Current dividend \(D_t\).

  • rate (float) – Discount rate per period.

  • rho (float) – Autocorrelation of dividends, in [0, 1).

  • mean (float) – Long-run dividend \(\bar D\).

Return type:

ndarray | float

Returns:

float or ndarray

Examples

>>> round(ar1_dividend_price(1.0, 0.05, 0.9, 1.0), 12)
20.0
financialkit.asset_pricing.capm_equilibrium(expected_returns, cov, risk_free)[source]#

The market portfolio and betas of a mean-variance economy with a riskless asset.

Parameters:
  • expected_returns (ArrayLike)

  • cov (ArrayLike)

  • risk_free (float) – Must lie below the minimum-variance portfolio’s mean, so that the tangency portfolio is on the efficient branch.

Return type:

CAPMEquilibrium

Returns:

CAPMEquilibrium – Every asset lies on the security market line: sml_errors is zero.

financialkit.asset_pricing.capm_expected_return(beta, risk_free, market_return)[source]#

The security market line, \(r_f + \beta (E[r_m] - r_f)\).

Parameters:
Return type:

ndarray | float

Returns:

float or ndarray

Examples

>>> round(capm_expected_return(1.5, 0.03, 0.08), 12)
0.105
financialkit.asset_pricing.ccapm_expected_excess_return(consumption_beta, consumption_vol, gamma)[source]#

Breeden’s consumption CAPM, \(E[R_i] - R_f \approx \gamma\, \beta_{i,c}\, \sigma_c^2\).

The first-order form of \(E[R_i] - R_f = -R_f \mathrm{Cov}(m, R_i)\) with \(m \approx \beta(1 - \gamma \Delta c)\): the premium is risk aversion times the covariance of the return with consumption growth. It is exact for log returns in LucasTree.

Parameters:
  • consumption_beta (ArrayLike) – \(\mathrm{Cov}(R_i, \Delta c) / \mathrm{Var}(\Delta c)\), for example from estimate_beta().

  • consumption_vol (float) – Volatility of consumption growth.

  • gamma (float) – Relative risk aversion.

Return type:

ndarray | float

Returns:

float or ndarray

Examples

>>> round(ccapm_expected_excess_return(2.0, 0.02, 5.0), 12)
0.004
financialkit.asset_pricing.dividend_discount_value(dividends, rate, terminal_growth=None)[source]#

Williams’s investment value: the present value of a share’s dividends.

Parameters:
  • dividends (ArrayLike) – Dividends forecast for periods 1 .. n.

  • rate (float) – Required return per period.

  • terminal_growth (float | None) – If given, dividends after period n grow at this rate forever, and their Gordon value at n is discounted back and added. If omitted, the share is worth only the n dividends shown.

Return type:

float

Returns:

float

Examples

Three dividends of 1, 1.1 and 1.2, then 3% growth, at a 10% required return:

>>> round(dividend_discount_value([1.0, 1.1, 1.2], 0.10, terminal_growth=0.03), 4)
15.9858
financialkit.asset_pricing.estimate_beta(returns, market_returns)[source]#

Sample beta \(\mathrm{Cov}(r_i, r_m) / \mathrm{Var}(r_m)\).

Parameters:
Return type:

ndarray | float

Returns:

float or ndarray, shape (n,)

Examples

>>> estimate_beta([0.02, -0.04, 0.06], [0.01, -0.02, 0.03])
2.0
financialkit.asset_pricing.ex_post_rational_price(dividends, rate, terminal_price)[source]#

Shiller’s \(p^*_t\): the value of the dividends that were actually paid.

\(p^*_t = (p^*_{t+1} + D_{t+1}) / (1 + r)\), run backwards from \(p^*_T\) = terminal_price.

Parameters:
  • dividends (ArrayLike) – Dividend paid at the end of each period 0 .. T-1; dividends[t + 1] is received by the holder at date t.

  • rate (float) – Constant discount rate per period.

  • terminal_price (float) – Value placed on the share at the last date (Shiller used the sample-average price).

Return type:

ndarray

Returns:

ndarray, shape (T,)

Examples

>>> ex_post_rational_price([1.0, 1.0, 1.0], 0.0, 5.0).tolist()
[7.0, 6.0, 5.0]
financialkit.asset_pricing.fama_macbeth(excess_returns, factors=None, betas=None)[source]#

Fama and MacBeth’s two-pass estimate of factor risk premia.

First pass: each asset’s betas, from full-sample time-series regressions on factors (or supplied directly as betas). Second pass: each period, a cross-sectional regression of the excess returns on a constant and the betas. The premia are the time averages of the slopes, with standard errors from their time-series variation, which absorbs cross-sectional correlation of the errors.

Parameters:
Return type:

FamaMacBethResult

Returns:

FamaMacBethResult – premia[0] is the average zero-beta excess return (zero if the model holds), premia[1:] the factor premia.

financialkit.asset_pricing.gordon_growth_price(next_dividend, rate, growth)[source]#

Gordon’s price of a share whose dividends grow at a constant rate, \(D_1 / (r - g)\).

Parameters:
  • next_dividend (ArrayLike) – Dividend paid one period from now, \(D_1\).

  • rate (ArrayLike) – Required return \(r\), greater than growth.

  • growth (ArrayLike) – Dividend growth rate \(g\).

Return type:

ndarray | float

Returns:

float or ndarray

Examples

>>> gordon_growth_price(2.0, 0.09, 0.04)
40.0
financialkit.asset_pricing.grs_test(excess_returns, factors)[source]#

Gibbons, Ross and Shanken’s F-test that all time-series alphas are zero.

\[F = \frac{T - N - K}{N}\, \frac{\hat\alpha' \hat\Sigma^{-1} \hat\alpha}{1 + \bar f' \hat\Omega^{-1} \bar f} \sim F_{N,\, T - N - K}\]

with \(\hat\Sigma\) and \(\hat\Omega\) the maximum-likelihood residual and factor covariances. The statistic measures how much the squared Sharpe ratio of the tangency portfolio improves when the test assets are added to the factors.

Parameters:
  • excess_returns (ArrayLike) – Test assets, with n < T - k.

  • factors (ArrayLike) – Traded factor excess returns.

Return type:

GRSResult

Returns:

GRSResult

financialkit.asset_pricing.hansen_jagannathan_bound(mean_returns, cov, sdf_means)[source]#

The smallest volatility of a discount factor that prices a set of gross returns.

For \(E[m R] = 1\) with \(E[m] = v\), \(\sigma^2(m) \ge (\mathbf 1 - v \mu)' \Sigma^{-1} (\mathbf 1 - v \mu)\), attained by \(m^* = v + (\mathbf 1 - v\mu)'\Sigma^{-1}(R - \mu)\).

Parameters:
  • mean_returns (ArrayLike) – Expected gross returns of risky assets.

  • cov (ArrayLike) – Their covariance, nonsingular.

  • sdf_means (ArrayLike) – Values of \(E[m]\), the inverse of a candidate riskless return.

Return type:

HJBound

Returns:

HJBound

Examples

One asset: the bound is \(|1 - v\mu| / \sigma\).

>>> hansen_jagannathan_bound([1.07], [[0.0289]], [0.99]).sdf_stds.round(4).tolist()
[0.3488]
financialkit.asset_pricing.implied_cost_of_equity(price, next_dividend, growth)[source]#

The required return that the Gordon model reads off a price, \(D_1 / P + g\).

Parameters:
Return type:

ndarray | float

Returns:

float or ndarray – Dividend yield plus growth.

Examples

>>> round(implied_cost_of_equity(40.0, 2.0, 0.04), 12)
0.09
financialkit.asset_pricing.implied_risk_aversion(equity_premium, equity_vol, consumption_vol, correlation=1.0)[source]#

The risk aversion that the consumption CAPM needs to explain a premium.

\(\gamma = \dfrac{E[R_e] - R_f}{\rho\, \sigma_e\, \sigma_c}\): the Sharpe ratio divided by the volatility of consumption growth, scaled up by the imperfect correlation between the two.

Parameters:
  • equity_premium (float)

  • equity_vol (float)

  • consumption_vol (float)

  • correlation (float) – Correlation of equity returns with consumption growth.

Return type:

float

Returns:

float

Examples

Mehra and Prescott’s sample (premium 6.18%, equity volatility 16.54%, consumption volatility 3.57%), with perfect correlation:

>>> round(implied_risk_aversion(0.0618, 0.1654, 0.0357), 1)
10.5
financialkit.asset_pricing.jensen_alpha(excess_returns, market_excess_returns)[source]#

Jensen’s alpha: the intercept of a regression of excess returns on the market’s.

Parameters:
  • excess_returns (ArrayLike) – Fund (or asset) returns minus the riskless rate.

  • market_excess_returns (ArrayLike)

Return type:

FactorRegressionResult

Returns:

FactorRegressionResult – alphas per period and their t-statistics alpha_t.

financialkit.asset_pricing.levered_cost_of_equity(asset_return, debt_return, debt_to_equity, tax_rate=0.0)[source]#

Modigliani-Miller Proposition II: the expected return on levered equity.

\(r_E = r_A + (r_A - r_D)(1 - t) D / E\).

Parameters:
  • asset_return (ArrayLike) – Required return on the firm’s assets (the unlevered cost of capital).

  • debt_return (ArrayLike) – Required return on its debt.

  • debt_to_equity (ArrayLike) – Market-value leverage \(D / E\).

  • tax_rate (float) – Corporate tax rate; 0 gives the 1958 proposition, a positive value the 1963 correction with perpetual debt.

Return type:

ndarray | float

Returns:

float or ndarray

Examples

>>> round(levered_cost_of_equity(0.10, 0.05, 1.0), 12)
0.15
financialkit.asset_pricing.levered_firm_value(unlevered_value, debt, tax_rate=0.0)[source]#

Modigliani-Miller Proposition I: \(V_L = V_U + t D\).

Without taxes the value of the firm does not depend on its debt; with a corporate tax and permanent debt the tax shield adds \(t D\).

Parameters:
Return type:

ndarray | float

Returns:

float or ndarray

Examples

>>> levered_firm_value(100.0, 40.0), levered_firm_value(100.0, 40.0, tax_rate=0.25)
(100.0, 110.0)
financialkit.asset_pricing.long_short_factor(signal, returns, quantile=0.3)[source]#

Return of the top quantile of assets by signal minus the bottom quantile.

Parameters:
  • signal (ArrayLike) – High values go long: pass minus the size to get SMB, the book-to-market ratio to get HML, the past return to get UMD.

  • returns (ArrayLike)

  • quantile (float) – Fraction of assets in each leg, in (0, 0.5] (Fama and French use 30%).

Return type:

ndarray

Returns:

ndarray, shape (T,)

Examples

>>> round(float(long_short_factor([1.0, 2.0, 3.0, 4.0], [[0.01, 0.02, 0.03, 0.05]], 0.5)[0]), 12)
0.025
financialkit.asset_pricing.max_sharpe_ratio(expected_excess_returns, cov)[source]#

The largest Sharpe ratio of any portfolio, \(\sqrt{\mu' \Sigma^{-1} \mu}\).

Hansen and Jagannathan’s bound in its simplest form: \(\sigma(m)/E(m)\) is at least this number.

Parameters:
Return type:

float

Returns:

float

Examples

>>> round(max_sharpe_ratio([0.06], [[0.04]]), 12)
0.3
financialkit.asset_pricing.momentum_signal(returns, lookback=12, skip=1)[source]#

Jegadeesh-Titman momentum: the compound return over months t - lookback to t - skip - 1.

Parameters:
  • returns (ArrayLike) – Simple returns.

  • lookback (int) – Length of the formation window, including the skipped months.

  • skip (int) – Most recent months left out (one month avoids short-term reversal).

Return type:

ndarray

Returns:

ndarray, shape (T, n) – Signal available at the start of each period; the first lookback rows are nan.

Examples

>>> import numpy as np
>>> momentum_signal(np.full((4, 1), 0.1), lookback=3, skip=1)[3].round(12).tolist()
[0.21]
financialkit.asset_pricing.simulate_factor_model(n_periods, betas, factor_means, factor_cov, idio_vol=0.05, alphas=None, rng=None)[source]#

Normal factor returns and independent normal residuals.

Parameters:
Return type:

FactorPanel

Returns:

FactorPanel

Examples

>>> panel = simulate_factor_model(120, [0.5, 1.0, 1.5], [0.006], [[0.002]], rng=0)
>>> panel.excess_returns.shape, panel.factors.shape
((120, 3), (120, 1))
financialkit.asset_pricing.sort_portfolios(signal, returns, n_groups=10)[source]#

Equal-weighted returns of portfolios formed on signal, lowest group first.

Parameters:
  • signal (ArrayLike) – Sorting characteristic, known when the period’s returns begin; a vector is a characteristic that does not change. nan drops an asset from that period’s sort.

  • returns (ArrayLike)

  • n_groups (int)

Return type:

ndarray

Returns:

ndarray, shape (T, n_groups) – nan in periods with fewer valid assets than groups.

Examples

>>> sort_portfolios([3.0, 1.0, 2.0, 4.0], [[0.3, 0.1, 0.2, 0.4]], n_groups=2).tolist()
[[0.15000000000000002, 0.35]]
financialkit.asset_pricing.sustainable_growth(return_on_equity, payout_ratio)[source]#

Gordon’s growth rate of a firm that reinvests its retained earnings, \(g = b \cdot ROE\).

Parameters:
  • return_on_equity (ArrayLike) – Return earned on reinvested equity.

  • payout_ratio (ArrayLike) – Share of earnings paid as dividends, so b = 1 - payout_ratio is retained.

Return type:

ndarray | float

Returns:

float or ndarray

Examples

>>> round(sustainable_growth(0.15, 0.6), 12)
0.06
financialkit.asset_pricing.time_series_regression(excess_returns, factors)[source]#

Regress each asset’s excess return on the factors, with an intercept.

This is the test of a model whose factors are traded excess returns: the CAPM with the market, Fama and French’s three factors, or Carhart’s four. A single factor reproduces Jensen’s alpha.

Parameters:
  • excess_returns (ArrayLike) – Excess returns of the test assets.

  • factors (ArrayLike) – Factor returns.

Return type:

FactorRegressionResult

Returns:

FactorRegressionResult

Examples

>>> import numpy as np
>>> f = np.array([0.01, -0.02, 0.03, 0.00, 0.02])
>>> res = time_series_regression(0.001 + 1.5 * f, f)
>>> res.alphas.round(12).tolist(), res.betas.round(12).tolist()
([0.001], [[1.5]])
financialkit.asset_pricing.variance_bound(price, dividends, rate, terminal_price=None)[source]#

Compare the volatility of a price with that of its ex-post rational price.

If \(p_t = E_t[p^*_t]\), then \(p^*_t = p_t + u_t\) with a forecast error \(u_t\) uncorrelated with \(p_t\), so \(\sigma(p) \le \sigma(p^*)\).

Parameters:
  • price (ArrayLike) – Actual (detrended) price.

  • dividends (ArrayLike) – Matching (detrended) dividends.

  • rate (float) – Discount rate per period.

  • terminal_price (float | None) – Value of \(p^*\) at the last date; the sample-average price by default.

Return type:

ExcessVolatilityResult

Returns:

ExcessVolatilityResult

financialkit.asset_pricing.wacc(equity_return, debt_return, debt_to_value, tax_rate=0.0)[source]#

Weighted average cost of capital, \((1 - L) r_E + L r_D (1 - t)\) with \(L = D / V\).

Parameters:
Return type:

ndarray | float

Returns:

float or ndarray

Examples

With the equity return from Proposition II, the WACC is the asset return:

>>> round(wacc(0.15, 0.05, 0.5), 12)
0.1
financialkit.asset_pricing.zero_beta_capm(expected_returns, cov, zero_beta_rate)[source]#

Black’s CAPM without a riskless asset.

Any efficient portfolio \(m\) prices every asset linearly, \(E[r_i] = E[r_z] + \beta_{im} (E[r_m] - E[r_z])\), where \(z\) is the minimum-variance portfolio uncorrelated with \(m\). Here the market is the efficient portfolio whose zero-beta rate is zero_beta_rate: the frontier point where a tangent from that rate touches it.

Parameters:
  • expected_returns (ArrayLike)

  • cov (ArrayLike)

  • zero_beta_rate (float) – Below the minimum-variance portfolio’s mean.

Return type:

ZeroBetaResult

Returns:

ZeroBetaResult