toolkit package

Module contents

Financial Toolkit Module

Apply data science and machine learning concepts to real-world investment problems

Submodules

toolkit.data module

Pull data from various sources

  • Yahoo! Finance

  • Ken French’s Data Library

  • Federal Reserve Economic Data

  • Bank of Canada

  • Statistics Canada

  • MSCI

  • With Intelligence

  • S&P

toolkit.data.end_of_month(date: date = None, n: int = 0) date

Last day of the month that is n months after the specified date. Similar to the EOMONTH function in Excel.

Parameters

datedatetime.date, optional

A date, by default None (i.e. today)

nint, optional

Number of months, by default 0. A positive value yields a month in the future, a negative value yields a month in the past.

Returns

datetime.date

_description_

toolkit.data.end_of_quarter(date: date = None, n: int = 0) date

Last day of the calendar quarter that is n quarters after the specified date.

Parameters

datedatetime.date, optional

A date, by default None (i.e. today)

nint, optional

Number of quarters, by default 0. A positive value yields a quarter in the future, a negative value yields a quarter in the past.

Returns

datetime.date

_description_

toolkit.data.end_of_year(date: date = None, n: int = 0) date

Last date of the calendar year that is n years after the specified date.

Parameters

datedatetime.date, optional

A date, by default None (i.e. today)

nint, optional

Number of years, by default 0. A positive value yields a year in the future, a negative value yields a year in the past.

Returns

datetime.date

_description_

toolkit.data.get_boc_bulk(ids: list = ['V80691342'], start_date: date = None, end_date: date = None) DataFrame

Download the historical data from Bank of Canada

Parameters

idslist

List of series names, by default [“V80691342”], i.e. 1 month Treasury bill

startdatetime.date, optional

Start date, by default end_of_month(n=-25)

enddatetime.date, optional

End date, by default end_of_month()

Returns

pd.DataFrame

_description_

toolkit.data.get_bulk_withintelligence(codes: list = [11469]) DataFrame

Download the historical returns of selected hedge fund indexes.

Returns

pd.DataFrame

Time series of the monthly returns.

toolkit.data.get_famafrench_datasets() list

Get the list of datasets related to factor analysis

Returns:

list: List of dataset names in str

toolkit.data.get_famafrench_factors(dataset: str, add_momentum: bool = False) DataFrame
toolkit.data.get_fred_bulk(ids: list = ['SOFR'], start_date: date = None, end_date: date = None) DataFrame

Download the historical Federal Reserve Economic Data (FRED) from Frederal Reserver Bank of St. Louis

Parameters

idslist, optional

List of series Ids, by default [“SOFR”], i.e. Secured Overnight Financing Rate

startdatetime.date, optional

Start date, by default 2 years before today

enddatetime.date, optional

End date, by default today

Returns

pd.DataFrame

Index is DatetimeIndex (freq=’ME’)

toolkit.data.get_msci(codes: list = [990100], end_date: str = None, fx: str = 'USD', variant: str = 'STRD', freq: str = 'END_OF_MONTH', ror: bool = True) DataFrame

Download the historical index value of multiple indexes.

Parameters

codeslist

List of MSCI index code, by default [990100], i.e. MSCI World See https://www.msci.com/our-solutions/indexes/index-resources/index-tools

end_datestr, optional

As of date, by default get_last_business_day().strftime(“%Y%m%d”)

fxstr, optional

Currency, by default “USD”

variantstr, optional

Index Level (‘STRD’ for Price, ‘NETR’ for Net, ‘GRTR’ for Gross), by default “STRD”

freqstr, optional

Data Frequency, by default “END_OF_MONTH”

rorbool, optional

Convert from index value to return, by default True

Returns

pd.DataFrame

Time series of the index values. Index is DatetimeIndex (freq=None).

toolkit.data.get_spglobal_bulk(codes: list = [5457755]) DataFrame

Download the historical index values from S&P Global

Parameters

codeslist, optional

List of index code, by default [5457755]

Returns

pd.DataFrame

Index is DatetimeIndex (freq=’B’)

toolkit.data.get_statcan_bulk(ids: list = [2062815], n: int = 25) DataFrame

Download the historical data from Statisticas Canada

Parameters

idslist

List of vectors, by default [2062815]. (Vector number is a 10-digit number without leading “V”)

nint, optional

Number of months, by default 24

Returns

pd.DataFrame

Column names are ids. Index is DatetimeIndex (freq=None).

toolkit.data.get_us_yield_curve(year: int = 0, n: int = 2) DataFrame

Download the historical Treasury Par Yield Curve Rates

Parameters

yearint, optional

Year, by default the current year

nint, optional

Number of years, by default 2

Returns

pd.DataFrame

Index is DatetimeIndex (freq=None)

toolkit.data.get_withintelligence(code: int) Series

Download the historical returns of selected hedge fund index.

Returns

pd.Series

Time series of the monthly returns.

toolkit.data.get_yahoo(ticker: str = '^GSPC', period: str = 'max') Series

Download the historical adjusted closing price of a security with ticker ticker.

Args:

ticker (str): Yahoo! ticker of the security, by default “^GSPC”, i.e. S&P 500

periodstr, optional

Length of track record to download, by default ‘max’

Returns:

pd.Series: Time series of the prices of the security

toolkit.data.get_yahoo_bulk(tickers: list = ['^GSPC'], period: str = 'max') DataFrame

Download the historical adjusted closing price of multiple securities with ticker in the tickers list.

Parameters

tickerslist

List of Yahoo! tickers

periodstr, optional

Length of track record to download, by default ‘max’

Returns

pd.DataFrame

Time series of the prices of the securities

toolkit.data.last_business_day(date: date = None)

toolkit.black_scholes module

Option Greeks

All functions share the same signature and are vectorized.

toolkit.black_scholes.bp(face: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25) float | ndarray

Present value of a zero-coupon bond, using continuous compounding.

Auxiliary method to verify put-call parity hold.

Parameters

facefloat | np.ndarray

Face value of the bond, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

Returns

float | np.ndarray

Present value of a zero-coupon bond.

toolkit.black_scholes.d1(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Probability of an European option being exercised.

\[d_1 = \frac{\ln(S/K) + (r - q + \frac{1}{2}\sigma^2)\tau}{\sigma\sqrt{\tau}}\]

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Probability of an European option being exercised.

toolkit.black_scholes.d2(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Probability of an European option not being exercised.

\[d_2 = \frac{\ln(S/K) + (r - q - \frac{1}{2}\sigma^2)\tau}{\sigma\sqrt{\tau}} = d_1 - \sigma\sqrt{\tau}\]

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Probability of an European option not being exercised.

toolkit.black_scholes.delta_call(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Delta of an European call option.

Delta is the rate of change of the option price with respect to the price of the underlying asset.

For a call option with delta of 0.5, its value will increase by $5 when the price of the underlying asset increases by $10.

\[\Delta_{call} = e^{-q \tau} \Phi(d_1)\]

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Delta of the call option, in the same shape as spot.

toolkit.black_scholes.delta_put(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Delta of an European put option.

\[\Delta_{put} = -e^{-q \tau} \Phi(-d_1)\]

Delta is the rate of change of the option price with respect to the price of the underlying asset.

For a put option with delta of -0.5, its value will decrease by $5 when the price of the underlying asset increases by $10.

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Delta of the put option, in the same shape as spot.

toolkit.black_scholes.gamma(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Gamma of an European call/put option.

\[\Gamma = e^{-q \tau} \frac{\varphi(d_1)}{S\sigma\sqrt{\tau}} = K e^{-r \tau} \frac{\varphi(d_2)}{S^2\sigma\sqrt{\tau}}\]

Gamma is the rate of change of the portfolio’s delta with respect to the price of the underlying asset.

For an option with gamma of 0.1, its delta will increase by 0.5 when the price of the underlying asset increase by $5. The value of the option will approximately increase by $frac{1}{2}Gamma times (delta S)^2$ which is $1.25.

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Gamma of the option, in the same shape as spot.

toolkit.black_scholes.price_call(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Fair value of an European call option.

\[V_{call} = Se^{-q \tau}\Phi(d_1) - e^{-r \tau} K\Phi(d_2)\]

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Fair value of the call option, in the same shape as spot.

toolkit.black_scholes.price_put(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Fair value of an European put option.

\[V_{put} = e^{-r \tau} K\Phi(-d_2) - Se^{-q \tau}\Phi(-d_1)\]

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Fair value of the put option, in the same shape as spot.

toolkit.black_scholes.rho_call(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Rho of an European call option.

\[\rho_{call} = K \tau e^{-r \tau}\Phi(d_2)\]

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Rho of the call option, in the same shape as spot.

toolkit.black_scholes.rho_put(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Rho of an European put option.

\[\rho_{put} = -K \tau e^{-r \tau}\Phi(-d_2)\]

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Rho of the put option, in the same shape as spot.

toolkit.black_scholes.theta_call(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Theta(call) of an European call option.

\[\Theta_{call} = e^{-q \tau} \frac{S \varphi(d_1) \sigma}{2 \sqrt{\tau}} - rKe^{-r \tau}\Phi(d_2) + qSe^{-q \tau}\Phi(d_1)\]

Theta is the rate of change of the value of the portfolio with respect to the passage of time.

For an option with theta of -4, its value will decrease by $4 / 252 per trading day.

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Theta of the call option, in the same shape as spot.

toolkit.black_scholes.theta_put(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Theta of an European put option.

\[\Theta_{put} = e^{-q \tau}\frac{S \varphi(d_1) \sigma}{2 \sqrt{\tau}} + rKe^{-r \tau}\Phi(-d_2) - qSe^{-q \tau}\Phi(-d_1)\]

Theta is the rate of change of the value of the portfolio with respect to the passage of time.

For an option with theta of -4, its value will decrease by $4 / 252 per trading day.

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Theta of the put option, in the same shape as spot.

toolkit.black_scholes.vega(strike: float = 100.0, spot: float | ndarray = 100.0, rate: float = 0.05, time: float = 0.25, vol: float = 0.2, dvd: float = 0.0) float | ndarray

Vega of an European call/put option.

\[\mathcal{V} = S e^{-q \tau} \varphi(d_1) \sqrt{\tau} = K e^{-r \tau} \varphi(d_2) \sqrt{\tau}\]

Vega is the rate of change of the value of the portfolio with respect to the volatility of the underlying asset. For an option with vega of 15, its value will increase by $0.15 when the volatility of the underlying asset increase by 0.01 (e.g. from 20% to 21%).

In practice, financial data providers often report vega as vega per basis point, which is the “textbook” vega / 100. In such case, the value of an option with vega of 0.15 will increase by $0.15 when the volatility of the underlying increase by 1%.

Parameters

strikefloat, optional

Strike price, by default 100.

spotfloat | np.ndarray, optional

Stock price, by default 100.

ratefloat, optional

Risk-free rate in decimal, by default 0.05 (i.e. 5%)

timefloat, optional

Time to maturity, number of years in decimal, by default 0.25 (i.e. 3 months)

volfloat, optional

Volatility in decimal, by default 0.2 (i.e. 20%)

dvdfloat, optional

Annual dividend yield in decimal, by default 0. (i.e. non-dividend paying)

Returns

float | np.ndarray

Vega of the option, in the same shape as spot.

toolkit.functional module

Most frequently used formulas in quantitative finance.

Functions are all vectorized and work for both Series and DataFrame.

Accept both time series of prices or returns as the input.

toolkit.functional.active_return(timeseries: Series | DataFrame, benchmark: Series | DataFrame, annualize=True) float | Series

Arithmetic excess return over benchmark

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

annualizebool, optional

Specify if active return should be annualized, by default False

Returns

float | pd.Series

Excess return

toolkit.functional.all_drawdown(timeseries: Series | DataFrame) Series | DataFrame

All drawdowns, sorted in descending order of magnitude

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of prices

Returns

pd.Series | pd.DataFrame

Series or DataFrame of drawdowns

toolkit.functional.alpha(timeseries: Series | DataFrame, benchmark: Series | DataFrame, rfr_periodic: float | Series = 0, annualize=False) float | Series

Jensen’s alpha(s)

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series | pd.DataFrame

Benchmark or factor returns. Use Series for simple regression or DataFrame for multiple regression.

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

annualizebool, optional

Specify if alpha should be annualized, by default False Note that alpha is annualized by multiplying it by number of periods in a year. See Bacon’s book for other ways of annualizing regression alpha or Jensen’s alpha.

Returns

float | pd.Series

Jensen’s alpha(s), return type varies depending on the inputs

1. Simple or multiple regression on a single portfolio (i.e. timeseries is a Series, benchmark is either a Series or a DataFrame) Return type is a float. 2. Simple or multiple regression on k portfolios (i.e. timeseries is a DataFrame, benchmark is either a Series or a DataFrame) Return type is a Series of shape (k,).

toolkit.functional.arithmetic_mean(timeseries: Series | DataFrame) float | Series

Arithmetic mean of returns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Arithmetic mean(s) of returns

toolkit.functional.avg_annual_drawdown(timeseries: Series | DataFrame) float | Series

Average drawdown by calendar year

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Average annual drawdown

toolkit.functional.avg_drawdown(timeseries: Series | DataFrame, d: int = 3) float | Series

Average of the d largest drawdowns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of prices

dint, optional

Number of observations, by default 3

Returns

float | pd.Series

Average of the d largest drawdowns

toolkit.functional.avg_neg(timeseries: Series | DataFrame) float | Series

Average of the negative returns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Average of the negative returns

toolkit.functional.avg_pos(timeseries: Series | DataFrame) float | Series

Average of the positive returns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Average of the positive returns

toolkit.functional.bear_beta(timeseries: Series | DataFrame, benchmark: Series, rfr_periodic: float | Series = 0) float | Series

Bear beta is the beta of the regression during periods that benchmark returns are negative.

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

Returns

float | pd.Series

Bear beta, as float for single portfolio or Series for multiple portfolios

toolkit.functional.best_period(timeseries: Series | DataFrame) float | Series

Return of the best period

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Return of the best period

toolkit.functional.beta(timeseries: Series | DataFrame, benchmark: Series | DataFrame, rfr_periodic: float | Series = 0) float | Series

Regression beta(s) or factor loading(s)

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series | pd.DataFrame

Benchmark or factor returns. Use Series for simple regression or DataFrame for multiple regression.

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

Returns

float | pd.Series

Regression beta(s) or factor loading(s), return type varies depending on the inputs

1. Simple regression on a single portfolio (i.e. timeseries is a Series, benchmark is a Series) Return type is a float. 2. Multiple regression on a single portfolio (i.e. timeseries is a Series, benchmark is a DataFrame) against m benchmarks/factors Return type is a Series of shape (m,). 3. Simple regression on k portfolios (i.e. timeseries is a DataFrame, benchmark is a Series) Return type is a Series of shape (k,). 4. Multiple regression on k portfolios (i.e. timeseries is a DataFrame, benchmark is a DataFrame) against m benchmarks/factors Return type is a Series of shape (k,). Each value is another Series of shape (m,)

Note

Benchmark should be already NET of risk-free rate, so this method works for multi-factor analysis

toolkit.functional.beta_timing_ratio(timeseries: Series | DataFrame, benchmark: Series, rfr_periodic: float | Series = 0) float | Series

Beta timing ratio measures portfolio manager’s ability to time the market.

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

Returns

float | pd.Series

Beta timing ratio, as float for single portfolio or Series for multiple portfolios

toolkit.functional.bull_beta(timeseries: Series | DataFrame, benchmark: Series, rfr_periodic: float | Series = 0) float | Series

Bull beta is the beta of the regression during periods that benchmark returns are positive.

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

Returns

float | pd.Series

Bull beta(s), as float for single portfolio or Series for multiple portfolios

toolkit.functional.burke_modified(timeseries: Series | DataFrame, rfr_annualized: float = 0, d: int = 3) float | Series

Modified Burke ratio is a Sharpe-like ratio but uses drawdown deviation in the denominator.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

rfr_annualizedfloat, optional

Annualized risk-free rate, by default 0

dint, optional

Number of observations, by default 3

Returns

float | pd.Series

Modified Burke ratio

toolkit.functional.calmar(timeseries: Series | DataFrame, rfr_annualized: float = 0) float | Series

Calmar ratio (aka drawdown ratio) is a Sharpe-like ratio that uses maximum drawdown as the investor’s risk instead of standard deviation.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

rfr_annualizedfloat, optional

Annualized risk-free rate, by default 0

Returns

float | pd.Series

The Calmar ratio

toolkit.functional.carino(r: float, b: float) float

Smoothing algorithm for multi-period attribution

Parameters

rfloat

Portfolio return

bfloat

Benchmark return

Returns

float

Carino factor

toolkit.functional.compound_return(timeseries: Series | DataFrame, annualize=False) float | Series

Compound return of time series

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

annualizebool, optional

Annualizing the compound return, by default False

Returns

float | pd.Series

Compound return(s)

toolkit.functional.convert_fx(timeseries: Series | DataFrame, foreign: Series, domestic: Series) Series | DataFrame

Convert the time series from foreign currency to domestic currency.

Note

Yahoo always use direct quote. (vs Bloomberg use indirect quote for GBP/EUR/AUD/NZD)

Parameters

timeseriespd.Series | pd.DataFrame

Time series of asset(s). It can be a Series or DataFrame of either prices or returns, but not a mix of both.

foreignpd.Series

Foreign currency, which the currency that the asset is denominated

domesticpd.Series

Domestic currency, which is the currency of the investor’s home country

Returns

pd.Series | pd.DataFrame

Time series of the prices

toolkit.functional.correlation(timeseries: DataFrame) DataFrame

Correlation matrix

Parameters

timeseriespd.DataFrame

DataFrame of returns

Returns

pd.DataFrame

Correlation matrix

toolkit.functional.covariance(timeseries: DataFrame, annualize=False) DataFrame

Coveriance matrix

Parameters

timeseriespd.DataFrame

DataFrame of returns

annualizebool, optional

Specify if the coveriance matrix is annualized, by default False

Returns

pd.DataFrame

Coveriance matrix

toolkit.functional.cvar_historical(timeseries: Series | DataFrame, sig: float = 0.05) float | Series

Historical Conditional Value-at-Risk (CVaR).

Also known as Expected Shortfall (ES).

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

sigfloat, optional

Significance level (alpha), by default 0.05

Returns

float | pd.Series

CVaR, reported as a negative number

toolkit.functional.cvar_normal(timeseries: Series | DataFrame, sig: float = 0.05) float | Series

Gaussian Conditional Value-at-Risk (CVaR).

Also known as Expected Shortfall (ES).

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

sigfloat, optional

Significance level (alpha), by default 0.05

Returns

float | pd.Series

CVaR, reported as a negative number

toolkit.functional.down_capture(timeseries: Series | DataFrame, benchmark: Series | DataFrame) float | Series

Down-market capture ratio

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of portfolio returns

benchmarkpd.Series | pd.DataFrame

Series or DataFrame of benchmark returns. If timeseries is a Series, benchmark must also be a Series.

Returns

float | pd.Series

Down-market capture ratio

toolkit.functional.downside_potential(timeseries: Series | DataFrame, mar: float = 0) float | Series

Downside potential is the average sum of returns below target

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

Returns

float | pd.Series

Downside potential

toolkit.functional.downside_risk(timeseries: Series | DataFrame, mar: float = 0, annualize: bool = False, ddof: int = 0) float | Series

Downside Risk measures the variability of underperformance below a minimum target return. It is the denominator of a Sortino ratio.

Also know as Downside Deviation.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

annualizebool, optional

Specifiy if downside risk should be annualized, by default False

ddof: int, optional

Delta Degrees of Freedom, by default 0

Returns

float | pd.Series

Downside Risk

toolkit.functional.drawdown_deviation(timeseries: Series | DataFrame, d: int = 3) float | Series

Drawdown deviation measures the standard deviation of individual drawdowns. This is used the denominator of the Modified Burke ratio.

Note: This is not the same as downside deviation.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

dint, optional

Number of observations, by default 3

Returns

float | pd.Series

Drawdown deviation, always negative

toolkit.functional.geometric_mean(timeseries: Series | DataFrame) float | Series

Geometric mean of returns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Geometric mean(s) of returns

toolkit.functional.information_ratio(timeseries: Series | DataFrame, benchmark: Series | DataFrame) float | Series

Information ratio is a Sharpe-like ratio except it uses excess returns instead of absolute returns and tracking error (or relative risk) instead of absolute risk.

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

Returns

float | pd.Series

Information ratio

toolkit.functional.is_normal(timeseries: Series, sig: float = 0.01) bool

Bera‐Jarque statistic.

The test statistic is always nonnegative.

p-value > sig means null hypothesis of normality cannot be rejected.

Parameters

timeseriespd.Series

Series or DataFrame of returns

sigfloat, optional

Significance level (alpha), by default 0.01

Returns

bool

True if normal

toolkit.functional.kurt(timeseries: Series | DataFrame) float | Series

Sample excess kurtosis, normalized by N-1

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Excess kurtosis

toolkit.functional.martin(timeseries: Series | DataFrame, rfr_annualized: float = 0) float | Series

Martin ratio (or ulcer performance index) is a Sharpe-like ratio but uses the ulcer index in the denominator.

Also know as ulcer performance index.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

rfr_annualizedfloat, optional

Annualized risk-free rate, by default 0

Returns

float | pd.Series

Martin ratio

toolkit.functional.max_upturn(timeseries: Series | DataFrame) float | Series

Maximum upturn

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of prices

Returns

float | pd.Series

Maximum upturn

toolkit.functional.mean_abs_dev(timeseries: Series | DataFrame) float | Series

Mean absolute deviation (or mean deviation) of returns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Mean absolute deviation of returns

toolkit.functional.omega(timeseries: Series | DataFrame, mar: float = 0) float

Omega ratio measures the gain-loss ratio, i.e. Upside potential divided by Downside potential.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

Returns

float

Omega ratio

toolkit.functional.pain(timeseries: Series | DataFrame, rfr_annualized: float = 0) float | Series

The pain ratio is a Sharpe-like ratio but uses the pain index in the denominator.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

rfr_annualizedfloat, optional

Annualized risk-free rate, by default 0

Returns

float | pd.Series

Pain ratio

toolkit.functional.pain_index(timeseries: Series | DataFrame) float | Series

The pain index is similar to the ulcer index but use absolute value of the underwater instead of squaring.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Pain index

toolkit.functional.periodicity(timeseries: Series | DataFrame) int

Get the number of periods that make up a year.

Parameters

timeseriespd.Series | pd.DataFrame

Time series of returns or prices

Returns

int

Number of periods in a year

toolkit.functional.price_to_return(timeseries: Series | DataFrame) Series | DataFrame

Convert prices to returns.

Parameters

timeseriespd.Series | pd.DataFrame

Time series of prices

Returns

pd.Series | pd.DataFrame

Time series of returns

toolkit.functional.regress(timeseries: Series | DataFrame, benchmark: Series | DataFrame, rfr_periodic: float | Series = 0) Series | DataFrame

Perform single or multiple regression on portfolio returns over benchmarks or factors.

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series | pd.DataFrame

Benchmark or factor returns. Use Series for simple regression or DataFrame for multiple regression.

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

Returns

pd.Series | pd.DataFrame

Series or DataFrame of regression results Indices of the results are: ‘alpha’, ‘betas’, ‘r2’ and ‘r2adj’

1. Simple regression on a single portfolio (i.e. timeseries is a Series, benchmark is a Series) Return type is a Series of shape (4,) of type (float, float, float, float). 2. Multiple regression on a single portfolio (i.e. timeseries is a Series, benchmark is a DataFrame) Return type is a Series of shape (4,) of type (float, Series, float, float). 3. Simple regression on n portfolios (i.e. timeseries is a DataFrame, benchmark is a Series) Return type is a DataFrame of shape (4, n). Index types are (float, float, float, float). 4. Multiple regression on n portfolios (i.e. timeseries is a DataFrame, benchmark is a DataFrame) Return type is a DataFrame of shape (4, n). Index types (float, Series, float, float).

toolkit.functional.return_to_price(timeseries: Series | DataFrame) Series | DataFrame

Convert returns to prices.

Initial price is 1.

Parameters

timeseriespd.Series | pd.DataFrame

Time series of returns

Returns

pd.Series | pd.DataFrame

Time series of prices

toolkit.functional.rsquared(timeseries: Series | DataFrame, benchmark: Series | DataFrame, rfr_periodic: float | Series = 0, adjusted: bool = False) float | Series | DataFrame

Coefficient of determination (or R-squared) is the variation in the dependent variable that is explained by the independent variable(s).

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series | pd.DataFrame

Benchmark or factor returns. Use Series for simple regression or DataFrame for multiple regression.

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

adjustedbool, optional

Specify if R-squared should be penalized for including extra variables in the model, by default False

Returns

float | pd.Series | pd.DataFrame

R-squared, return type varies depending on the inputs

1. Simple or multiple regression on a single portfolio (i.e. timeseries is a Series, benchmark is either a Series or a DataFrame) Return type is a float. 2. Simple or multiple regression on k portfolios (i.e. timeseries is a DataFrame, benchmark is either a Series or a DataFrame) Return type is a Series of shape (k,).

toolkit.functional.sharpe(timeseries: Series | DataFrame, rfr_annualized: float = 0, annualize=True) float | Series

Sharpe ratio measures the reward to variability

Parameters

timeseriespd.Series | pd.DataFrame

Series of DataFrame of returns

rfr_annualizedfloat, optional

Annualized risk-free rate, by default 0

annualizebool, optional

Specify if returns and volatility are annualized, by default True

Returns

float | pd.Series

_description_

toolkit.functional.skew(timeseries: Series | DataFrame) float | Series

Sample skewness of returns, normalized by N-1

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Skewness

toolkit.functional.sortino(timeseries: Series | DataFrame, mar: float = 0, ddof: int = 0) float | Series

Sortino ratio is a Sharpe-like ratio that uses downside risk as the investor’s risk instead of standard deviation.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

ddofint, optional

Delta Degrees of Freedom, by default 0

Returns

float | pd.Series

Sortino ratio

toolkit.functional.sterling(timeseries: Series | DataFrame) float | Series

The original Sterling ratio proposed by Deane Sterling Jones is the ratio between cummulative annualized return and the average drawdown plus 10%.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Sterling ratio

toolkit.functional.sterling_calmar(timeseries: Series | DataFrame, rfr_annualized: float = 0) float | Series

Sterling-Calmar ratio is a Sharpe-like ratio that uses average annual drawdown as the investor’s risk instead of standard deviation.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

rfr_annualizedfloat, optional

Annualized risk-free rate, by default 0

Returns

float | pd.Series

Sterling-Calmar ratio

toolkit.functional.sterling_modified(timeseries: Series | DataFrame, rfr_annualized: float = 0, d: int = 3) float | Series

Modified Sterling ratio, proposed by Carl Bacon, is a Sharpe-like ratio that uses average largest drawdown as the investor’s risk instead of standard deviation.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

rfr_annualizedfloat, optional

Annualized risk-free rate, by default 0

dint, optional

Number of observations, by default 3

Returns

float | pd.Series

_description_

toolkit.functional.summary(timeseries: Series | DataFrame, benchmark: Series, rfr_periodic, mar: float = 0) dict

The most common performance and risk measures

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

rfr_periodic_type_

Periodic risk-free rate

marfloat, optional

Target periodic return, by default 0

Returns

dict

A dictionary of the common performance and risk measures

toolkit.functional.tracking_error(timeseries: Series | DataFrame, benchmark: Series | DataFrame, annualize: bool = False) float | Series

Tracking error (or tracking risk, relative risk, active risk) is the standard deviation of the difference between the returns of a portfolio and the benchmark

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

annualizebool, optional

Specify if tracking error should be annualized, by default False

Returns

float | pd.Series

Tracking error

toolkit.functional.treynor(timeseries: Series | DataFrame, benchmark: Series, rfr_periodic: float | Series = 0) float | Series

Treynor ratio (reward to volatility) is a Sharpe-like ratio that uses beta as the investor’s risk instead of standard deviation.

Parameters

timeseriespd.Series | pd.DataFrame

Portfolio returns. Use Series for a single portfolio or DataFrame for multiple portfolios.

benchmarkpd.Series

Benchmark returns

rfr_periodicfloat | pd.Series, optional

Annual risk-free rate, by default 0

Returns

float | pd.Series

Treynor ratio

toolkit.functional.ulcer_index(timeseries: Series | DataFrame) float | Series

The ulcer index is similar to drawdown deviation but also take into account the time being underwater.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Ulcer index

toolkit.functional.underwater(timeseries: Series | DataFrame) Series | DataFrame

Distance from its previous peak

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of prices

Returns

pd.Series | pd.DataFrame

Distance from its previous peak, always negative

toolkit.functional.up_capture(timeseries: Series | DataFrame, benchmark: Series | DataFrame) float | Series

Up-market capture ratio

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of portfolio returns

benchmarkpd.Series | pd.DataFrame

Series or DataFrame of benchmark returns. If timeseries is a Series, benchmark must also be a Series.

Returns

float | pd.Series

Up-market capture ratio

toolkit.functional.upside_potential(timeseries: Series | DataFrame, mar: float = 0) float | Series

Upside potential is the average sum of returns above target

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

Returns

float | pd.Series

Upside potential

toolkit.functional.upside_potential_ratio(timeseries: Series | DataFrame, mar: float = 0) float | Series

The upside potential ratio is the ration between upside potential and downside risk.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

Returns

float | pd.Series

Upside potential ratio

toolkit.functional.upside_risk(timeseries: Series | DataFrame, mar: float = 0, annualize: bool = False, ddof: int = 0) float | Series

Upside Risk measures the variability of outperformance above a minimum target return.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

annualizebool, optional

Specifiy if downside risk should be annualized, by default False

ddof: int, optional

Delta Degrees of Freedom, by default 0

Returns

float | pd.Series

Upside Risk

toolkit.functional.var_historical(timeseries: Series | DataFrame, sig: float = 0.05) float | Series

Historical Value-at-Risk

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

sigfloat, optional

Significance level (alpha), by default 0.05

Returns

float | pd.Series

VaR, reported as a negative number

toolkit.functional.var_modified(timeseries: Series | DataFrame, sig: float = 0.05) float | Series

Modified Value-at-Risk

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

sigfloat, optional

Significance level (alpha), by default 0.05

Returns

float | pd.Series

mVaR, reported as a negative number

toolkit.functional.var_normal(timeseries: Series | DataFrame, sig: float = 0.05) float | Series

Gaussian Value-at-Risk

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

sigfloat, optional

Significance level (alpha), by default 0.05

Returns

float | pd.Series

VaR, reported as a negative number

toolkit.functional.variability_skewness(timeseries: Series | DataFrame, mar: float = 0) float | Series

Variability skewness is the ratio of Upside risk compared to Downside risk.

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

marfloat, optional

Target periodic return, by default 0

Returns

float | pd.Series

Variability skewness

toolkit.functional.variance(timeseries: Series | DataFrame, annualize: bool = False) float | Series

Sample variance of returns with Bessel’s correction (i.e. divide by N-1 instead of N)

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

annualizebool, optional

Specify if variance should be annualized, by default False

Returns

float | pd.Series

Variance

toolkit.functional.vol_neg(timeseries: Series | DataFrame) float | Series

Sample standard deviation of the negative returns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Volatility of the negative returns

toolkit.functional.vol_pos(timeseries: Series | DataFrame) float | Series

Sample standard deviation of the positive returns

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Volatility of the positive returns

toolkit.functional.volatility(timeseries: Series | DataFrame, annualize=False)

Sample volatility of returns with Bessel’s correction (i.e. divide by N-1 instead of N)

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

annualizebool, optional

Specify if volatility should be annualized, by default False

Returns

float | pd.Series

Volatility

toolkit.functional.worst_drawdown(timeseries: Series | DataFrame) float | Series

Worst drawdown (or maximum drawdown)

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of prices

Returns

float | pd.Series

The worst drawdown which is always a negative number

toolkit.functional.worst_period(timeseries: Series | DataFrame) float | Series

Return of the worst period

Parameters

timeseriespd.Series | pd.DataFrame

Series or DataFrame of returns

Returns

float | pd.Series

Return of the worst period

toolkit.fixed_income module

Fixed-income module

Vectorized. Interest rate can be a Series of floating rates.

toolkit.fixed_income.bond_price(y: float | ndarray, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2) float

Present value of a bond as a percentage of face value

Parameters

yfloat | np.ndarray

Yield to maturity, annualized

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

Returns

float

Present value of a bond as a percentage of face value

toolkit.fixed_income.convexity(y: float | ndarray, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2) float

Convexity

Parameters

yfloat | np.ndarray

Yield to maturity, annualized

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

Returns

float

Convexity

toolkit.fixed_income.convexity_effective(y: float | ndarray, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2, delta=0.0025) float

Effective convexity

Parameters

yfloat | np.ndarray

Yield to maturity, annualized

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

deltafloat, optional

Parallel shift in interest rate, by default 0.0025 (i.e. 25 bps)

Returns

float

Effective convexity

toolkit.fixed_income.convexity_modified(y: float | ndarray, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2) float

Modified convexity, adjusted for when actual payment frequency.

Parameters

yfloat | np.ndarray

Yield to maturity, annualized

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

Returns

float

Modified convexity

toolkit.fixed_income.duration_effective(y: float | ndarray, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2, delta=0.0025) float

Effective duration

Parameters

yfloat | np.ndarray

Yield to maturity, annualized

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

deltafloat, optional

Parallel shift in interest rate, by default 0.0025 (i.e. 25 bps)

Returns

float

Effective duration

toolkit.fixed_income.duration_macaulay(y: float | ndarray, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2) float

Macaulay duration, which is the average time to receive the cash flows weighted by the present value of cash flows.

It assumes that coupon payments are reinvested continuously which is not the case.

Parameters

yfloat | np.ndarray

Yield to maturity, annualized

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

Returns

float

Macaulay duration

toolkit.fixed_income.duration_modified(y: float | ndarray, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2) float

Modified duration, adjusted for when actual payment frequency.

Parameters

yfloat | np.ndarray

Yield to maturity, annualized

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

Returns

float

Modified duration

toolkit.fixed_income.yield_to_maturity(price: float, coupon: float = 0.0, ttm: float = 1.0, freq: int = 2) float

Yield to maturity

Parameters

pricefloat

Market price as a percentage of face value

couponfloat, optional

Annual coupon rate, by default 0.0 (i.e. zero coupon)

ttmfloat, optional

Time to maturity in year, by default 1.0 (i.e. one year)

freqint, optional

Coupon frequency, by default 2 (i.e. semi-annual coupon)

Returns

float

Yield to maturity

toolkit.portfolio module

Portfolio Optimization Module

weights should be a Series with shape (m,)

or a DataFrame with shape (m, k)

returns should be a Series with shape (m,)

or a DataFrame with shape (n, m)

where:

n is the number of periods m is the number of asset classes k is the number of weighting schemes

toolkit.portfolio.equal_weight(er: Series) Series

Equal weight each asset in a portfolio.

Also known as naive diversification.

Parameters

erpd.Series

Expected returns

Returns

pd.Series

Weights of each asset

toolkit.portfolio.inverse_vol(cov: DataFrame) Series

Weight each asset based on the inverse of its volatility. It is sometimes called poor man’s risk parity.

Parameters

covpd.DataFrame

Coveriance matrix

Returns

pd.Series

Weight of each asset

toolkit.portfolio.max_return(er: Series) Series

Allocate 100% to the asset that generates the highest return, and 0% to the rest.

Parameters

erpd.Series

Expected returns

Returns

pd.Series

Weight of each asset

toolkit.portfolio.max_sharpe(er: Series, cov: DataFrame, rfr: float = 0.0, min: float = -inf, max: float = inf) Series

Weight of each asset in the portfolio that achieve the highest Sharpe ratio yet satisfy all constraints like no shorting and no leverage.

Periodicity of risk-free rate should match that of the expected return. If expected returns are annualized, risk-free rate should also be annualized.

Parameters

erpd.Series

Expected returns

covpd.DataFrame

Coveriance matrix

rfrfloat, optional

Risk-free rate, by default 0.

minfloat, optional

Minimum weight, by default float(‘-inf’) i.e. allow shorting. Set to 0 if no shorting is allowed.

maxfloat, optional

Maximum weight, by default float(‘inf’) i.e. allow leverage. Set to 1 if no leverage is allowed.

Returns

pd.Series

Weight of each asset

toolkit.portfolio.min_vol(cov: DataFrame) Series

Weight of each asset in the global minimum volatility portfolio.

Parameters

covpd.DataFrame

Coveriance matrix

Returns

pd.Series

Weight of each asset

toolkit.portfolio.min_vol_at(target: float, er: Series, cov: DataFrame, min: float = -inf, max: float = inf) Series

Weight of each asset in an optimal portfolio that generats the target return but has the smallest volatility.

This method can be used to generate the efficient frontier.

Parameters

targetfloat

Target return

erpd.Series

Expected returns

covpd.DataFrame

Coveriance matrix

minfloat, optional

Minimum weight, by default float(‘-inf’) i.e. allow shorting. Set to 0 if no shorting is allowed.

maxfloat, optional

Maximum weight, by default float(‘inf’) i.e. allow leverage. Set to 1 if no leverage is allowed.

Returns

pd.Series

Weight of each asset

toolkit.portfolio.portfolio_return(weights: Series | DataFrame, returns: Series | DataFrame) float64 | Series | DataFrame

Return(s) of the portfolio(s) based on input weight(s).

Parameters

weightspd.Series | pd.DataFrame

Portfolio weights

returnspd.Series | pd.DataFrame

Return(s) of each asset class over single or multiple period(s)

Returns

np.float64 | pd.Series | pd.DataFrame

Portfolio returns. See below for details.

When weights is a Series (i.e. Single weighting scheme)

If a Series of asset returns of a single period is passed, it outputs the return of buy-and-hold portfolio as a float (no rebancing).

If a DataFrame of asset returns over a period is passed, it outputs the time series of the of a constant-mix portfolio (rebalance every period) as a Series with shape (n,)

When weights is a DataFrame (i.e. Multiple weighting schemes):

If a Series of asset returns of a single period is passed, it outputs the return of k buy-and-hold portfolios as a Series with shape (k,).

If a DataFrame of asset returns over a period is passed, it outputs the time series of the of k constant-mix portfolios (rebalance every period) as a DataFrame with shape (n, k)

Note

Index of the weights must match that of the returns.

toolkit.portfolio.portfolio_volatility(weights: Series | DataFrame, cov: DataFrame) float64 | Series

Volatility of the portfolio(s) based on input weight(s).

Parameters

weightspd.Series | pd.DataFrame

Portfolio weights

covpd.DataFrame

Coveriance matrix

Returns

np.float64 | pd.Series

Portfolio volatilities. See below for details.

When weights is a Series (i.e. Single weighting scheme)

It outputs the portfolio volatility as a float.

When weights is a DataFrame (i.e. Multiple weighting schemes):

It outputs the volatilities of each portfolio as a Series with shape (k,)

Note: This method assumes the portfolio is buy-and-hold. To calculate the volatility of a constant-mix portfolio, please use portfolio_return to generate the portfolio returns and then call volatility.

toolkit.portfolio.risk_contribution(weights: Series | DataFrame, cov: DataFrame) Series | DataFrame

Risk contribution of each asset in the portfolio. Sum to 100%.

Parameters

weightspd.Series | pd.DataFrame

Portfolio weights

covpd.DataFrame

Coveriance matrix

Returns

pd.Series | pd.DataFrame

Risk contribution of each asset

toolkit.portfolio.risk_parity(cov: DataFrame) Series

Weight of each asset in an equal risk contribution portfolio.

Parameters

covpd.DataFrame

Coveriance matrix

Returns

pd.Series

Weight of each asset