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.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