Welcome to risktools’s documentation!

risktools.CAPM_beta(Ra, Rb, Rf=0, kind='all')

calculate single factor model (CAPM) beta

The single factor model or CAPM Beta is the beta of an asset to the variance and covariance of an initial portfolio. Used to determine diversification potential.

This function uses a linear intercept model to achieve the same results as the symbolic model used by code{link{BetaCoVariance}}

\[\beta_{a,b}=\frac{CoV_{a,b}}{\sigma_{b}}=\frac{\sum((R_{a}-\bar{R_{a}})(R_{b}-\bar{R_{b}}))}{\sum(R_{b}-\bar{R_{b}})^{2}}\]

Ruppert(2004) reports that this equation will give the estimated slope of the linear regression of \(R_{a}\) on \(R_{b}\) and that this slope can be used to determine the risk premium or excess expected return (see Eq. 7.9 and 7.10, p. 230-231).

kind=’bull’ and kind=’bear’ apply the same notion of best fit to positive and negative market returns, separately. kind=’bull’ is a regression for only positive market returns, which can be used to understand the behavior of the asset or portfolio in positive or ‘bull’ markets. Alternatively, kind=’bear’ provides the calculation on negative market returns.

The function timing_ratio may help assess whether the manager is a good timer of asset allocation decisions. The ratio, which is calculated as

\(TimingRatio =\frac{\beta^{+}}{\beta^{-}}\)

is best when greater than one in a rising market and less than one in a falling market.

While the classical CAPM has been almost completely discredited by the literature, it is an example of a simple single factor model, comparing an asset to any arbitrary benchmark.

Ra{array_like | DataFrame}

Array-like or DataFrame with datetime index of asset returns to be tested vs benchmark

Rbarray_like

Benchmark returns to use to test Ra

Rf{array_like | float}

risk free rate, in same period as your returns, or as a single digit average

kind{‘all’,’bear’,’bull’}, default ‘all’

Market type to return, by default ‘all’ ‘all’ : returns beta for all market types ‘bear’ : returns beta for bear markets ‘bull’ : returns beta for bull markets

If Ra is array-like, function returns beta as a scalar. If Ra is a DataFrame, it will return a series indexed with asset names from df columns

Sharpe, W.F. Capital Asset Prices: A theory of market equilibrium under conditions of risk. Journal of finance, vol 19, 1964, 425-442.

Ruppert, David. Statistics and Finance, an Introduction. Springer. 2004.

Bacon, Carl. Practical portfolio performance measurement and attribution. Wiley. 2004.

>>> import risktools as rt
>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["XOM","AAPL","SPY"],  "yahoo", datetime(2010,1,1), datetime(2017,12,31))
>>> df = df.pct_change()['Adj Close']
>>> df = df.asfreq('B')
>>> print(rt.CAPM_beta(df[['XOM','AAPL']], df['SPY'], Rf=0, kind='bear'))
>>> print(rt.CAPM_beta(df[['XOM','AAPL']], df['SPY'], Rf=0, kind='bull'))
>>> print(rt.CAPM_beta(df[['XOM','AAPL']], df['SPY'], Rf=0))
risktools.bond(ytm=0.05, c=0.05, T=1, m=2, output='price')

Compute bond price, cash flow table and duration

ytmfloat

Yield to Maturity

cfloat

Coupon rate per annum

Tfloat

Time to maturity in years

mfloat

Periods per year for coupon payments e.g semi-annual = 2.

outputstring

“price”, “df” or “duration”, by default “df”

Price scalar, cash flows data frame and/or duration scalar

>>> import risktools as rt
>>> rt.bond(ytm = 0.05, c = 0.05, T = 1, m = 2, output = "price")
>>> rt.bond(ytm = 0.05, c = 0.05, T = 1, m = 2, output = "df")
>>> rt.bond(ytm = 0.05, c = 0.05, T = 1, m = 2, output = "duration")
risktools.chart_eia_sd(market, key, start_dt='2010-01-01', output='chart', **kwargs)

Function for plotting and returning data from the EIA Supply & Demand Balances for refined oil products such as mogas, diesel, jet and resid.

market[‘mogas’, ‘diesel’, ‘jet’, ‘resid’]

Refined product type to build the S&D balance for

keystr

EIA API key

start_dtstr | datetime

Starting date for S&D balance data

output[‘chart’,’data’]

Output as a chart or return data as a dataframe, by default ‘chart’

pandas dataframe or a plotly figure object

>>> import risktools as rt
>>> fig = rt.chart_eia_sd('mogas', up['eia'])
>>> fig.show()
risktools.chart_eia_steo(key, start_dt=None, market='globalOil', output='chart', **kwargs)

Function to plot the global oil supply and demand balance using the US EIA data

keystr

Your EIA API key

start_dtstr | datetime

A string in the format of ‘YYYY-mm-dd’ or a datetime object

market[‘globalOil’]

What market to build the S&D balance for. For now, only globalOil working.

output[‘chart’, ‘data’], optional

What kind of output to return, by default ‘chart’

**kwargs

keyword arguments to pass to plotly.graph_objects.figure.update_layout function to modify figure

output = ‘chart’

Plotly figure object

output = ‘data’

dataframe

>>> import risktool as rt
>>> fig = rt.chart_eia_steo(up['eia'])
>>> fig.show()
risktools.chart_five_year_plot(df, **kwargs)

Function to output a 5 yr range plot for commodity prices

dfSeries

Series or single column dataframe with a datetime index

risktools.chart_forward_curves(df, code=None, cmdty=None, resample_freq=None, skip=5, curve_len=730, yaxis_title='$/BBL', **kwargs)

Chart forward curves of a futures contract strip

dfDataFrame

pandas DataFrame with a datetime index and columns representing the futures contract, ordered by most recent expiry

codestr, optional

commodity code to use to filter

cmdtystr, optional

expiry_table code to use to get expiry dates to plot forward curves. See data.open_data(‘expiry_data’) for allowable values, using the column ‘cmdty’

resample_freqstr, optional

pandas resample frequency type to downsample by. Assumes that new freq of lower periodicity than old freq. Uses mean to downsample

skipint

number of days between forward curves, must be 1 or greater

curve_lenint

how long the draw the curve on the plot, in days. Required if cmdty is not given.

uomstr

Unit of Measure to show on the final chart y-axis

***kwargs

keyword arguments to pass to fig.update_layout function for Plotly figures. Mainly to adjust figure layout.

Chart of forward curves varying with time

>>> import risktools as rt
>>> df = rt.data.open_data('dfwide')
>>> rt.chart_forward_curves(df, 'HO', yaxis_title='$/g', skip=10)
>>> rt.chart_forward_curves_new(df, 'HO', cmdty='cmeulsd', yaxis_title='$/g', skip=2)
risktools.chart_pairs(df, title='Time Series Pairs Plot', **kwargs)

Pairwise scatter matrix plot for timeseries

dfDataFrame

pandas DataFrame with a datetime index and columns representing the futures contract, ordered by most recent expiry

titlestr, optional

Chart title, by default “Time Series Pairs Plot”

**kwargs

keyword arguments to pass to plotly.graph_objects.Figure.update_layout function

risktools.chart_perf_summary(df, geometric=True, title=None)

Function to plot the cumulative performance and drawdowns of multiple assets

dfDataFrame | Series

wide dataframe with a datetime index and assets as columns or a series with a datetime index for a univariate chart

geometricbool

True to plot geometric returns, False to plot absolute

titlestr

Title for plot

>>> import risktools as rt
>>> df = rt.data.open_data('dfwide')
>>> df = df[['CL01', 'CL12', 'CL36']]
>>> df = rt.returns(df, period_return=1)
>>> rt.chart_perf_summary(df, title="Cummulative Returns and Drawdowns")
risktools.chart_spreads(username, password, pairs, days_from_expiry=200, feed=None, output='chart', start_dt='2012-01-01', **kwargs)

Chart commodity price spreads given as a list of tuple with two commodity codes and a name

usernamestr

username for Morningstar API

passwordstr

password for Morningstar API

pairsList of Tuples with String

A list of tuples of the format [(code_1, code_2, legend_label), (..,..,..)]. The spread calculated is then (code_1 - code_2). For example to plot the March/April time spread for NYMEX ULSD for 2014 & 2019, it would be [(@HO4H’, @HO4J’, ‘2014’), (@HO9H’, @HO9J’, ‘2019’)]

days_from_expiryint

Days from expiry of the earliest contract to start the plot from (i.e. 200 days). By default 200

feedstr

feed to use to get data from Morningstar

start_dtstr

Start date for the data retrival as a string, in the format “yyyy-mm-dd”

output[‘data’, ‘chart’]

whether to return data or a chart, by default ‘chart’

**kwargs

Arguments to pass to the plotly update_layout function to control the layout elements of the final figure. You can also modify the returned figure object if required.

a dataframe or a plotly figure object

>>> import risktools as rt
>>> df = rt.chart_spreads(
        username=up['m*']['user'],
        password=up['m*']['pass'],
        pairs=[('@HO4H', '@HO4J', '2014'), ('@HO9H', '@HO9J', '2019')],
        feed="CME_NymexFutures_EOD")
risktools.chart_zscore(df, freq=None, output='zscore', chart='seasons', **kwargs)

Function for calculating and plotting the seasonal decomposition and zscore of seasonal data Z-score is computed on the residuals conditional on their seasonal period. Beware that most seasonal charts in industry (i.e. NG Storage) is not detrended so results once you apply STL decomposition will vary from the unadjusted seasonal plot

dfSeries

Series with date and a values column. Datetime index must have a frequency defined (such as ‘D’, ‘B’, ‘W’, ‘M’ etc…)

freqstr, optional

Resampling frequency, by default None. Resamples using mean if downsampling. Not designed for upsampling.

output[‘stl’,’zscore’,’seasonal’]

‘stl’ - for seasonal decomposition object. Run the object method .plot() to plot the STL decomposition. Also use the object attributes “observed”, “resid”, “seasonal”, “trend” and “weights” to see components and calculate stats. ‘zscore’ - return residuals of szore ‘seasonal’ - for standard seasonal chart By default ‘zscore’

chartstr, optional

by default ‘seasons’

‘stl’ - Statsmodels STL object ‘seasonal’ - Plotly figure object ‘zscore’ - Plotly figure object

>>> df = rt.data.open_data('eiaStocks')
>>> df = df.loc[df.series=='NGLower48',['date','value']].set_index('date')['value']
>>> df = df.resample('W-FRI').mean()
>>> stl = rt.chart_zscore(df, freq='M')
>>> stl.plot()
>>> stl = rt.chart_zscore(df, output='seasonal')
>>> stl.show()
>>> stl = rt.chart_zscore(df, output='zscore')
>>> stl.show()
risktools.crr_euro(s=100, x=100, sigma=0.2, Rf=0.1, T=1, n=5, type='call')

European option binomial model on a stock without dividends. For academic purposes only. Use fOptions::CRRBinomialTreeOptions for real-life usage in R or Python equivalent.

sfloat

Stock price, by default 100

xfloat

Strike price, by default 100

sigmafloat

Implied volatility, by default 0.20

Rffloat

Risk-free rate, by default 0.1

Tfloat

Time to maturity in years, by default 1

n :

Number of time steps, by default 5. Internally dt = T/n.

typestr

“call” or “put”, by default “call”

List of asset price tree, option value tree and option price.

>>> import risktools as rt
>>> rt.crr_euro(s=100, x=100, sigma=0.2, Rf=0.1, T=1, n=5, type="call")
risktools.describe_distribution(x, discrete=False, boot=None, method='unbiased', graph=True, ax=None, **plot_args)

Function for generating population/sample statistics as well as plotting a Cullen and Frey graph for identifying distribution types based on data.

xiterable[numeric]

Data to be described

discretebool

True to show discrete distributions in the Cullen and Frey graph. By default False

bootint

If not None, function will bootstrap samples from the data to generate bootstrapped statistics for the Cullen and Frey graph

methodstr[“unbiased”|”sample”]

Method to be used to generate data statistics. If “sample” is used, statistics such as standard deviation, skewness and kurtosis will be calculated using the formulas for population samples (i.e. 1 degree of freedom). If “unbiased” is used, the calculations will use the formulas for the full population (i.e. 0 degrees of freedom). By default “unbiased”.

graphbool

If True, the function will return the Cullen and Frey graph for the data x. If False, it will return a dictionary with the population/sample statistics. By default True.

axmatplotlib Axes object

Only valid if graph = True. A matplotib axes object can be passed so that any graph generated by this function to added to the passed Axes object. Useful for adding the Cullen and Frey graph to a subplot. By default None.

**plot_args

Parameters to be passed to the matplotlib.pyplot.subplots() function. For example figsize=(10,10)

graph = False : returns a dictionary graph = True & ax is None : returns a matplotlib Figure object graph = True & ax is not None : returns a matplotlib Axes object

>>> import risktools as rt
>>> import matplotlib.pyplot as plt
>>> x = [1,4,7,9,15,20,54]
>>> rt.describe_distribution(x, method="sample", discrete=False, boot=500)
>>> fig, ax = plt.subplots(1,2)
>>> rt.describe_distribution(x, method="sample", discrete=False, boot=500, ax=ax[0], figsize=(10,10))
risktools.dist_desc_plot(x, figsize=(10, 10))

Provides a summary of returns’ distribution

xPandas Series

iterable of numeric returns

matplotlib Figure object

>>> import risktools as rt
>>> df = rt.data.open_data('dflong')
>>> x = df['BRN01'].pct_change().dropna()
>>> rt.dist_desc_plot(x)     
risktools.downside_deviation(R, MAR=0, method='full', potential=False)

Downside deviation, similar to semi deviation, eliminates positive returns when calculating risk. To calculate it, we take the returns that are less than the target (or Minimum Acceptable Returns (MAR)) returns and take the differences of those to the target. We sum the squares and divide by the total number of returns to get a below-target semi-variance.

This is also useful for calculating semi-deviation by setting MAR = mean(R)

RSeries or DataFrame

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

MARint

Minimum Acceptable Return, in the same periodicity as your returns

methodstr

Either “full” or “subset”, indicating whether to use the length of the full series or the length of the subset of the series below the MAR as the denominator, defaults to “full”

potentialbool

potential if True, calculate downside potential instead, by default False

*args :

any other passthru parameters

>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["SPY","AAPL"],  "yahoo", datetime(2000,1,1), datetime(2012,1,1))
>>> df = df.pct_change()
>>> df = df.asfreq('B')
>>> print(downside_deviation(df[('Adj Close','SPY')], MAR=0))
>>> print(downside_deviation(df['Adj Close'], MAR=0))
risktools.drawdowns(R, geometric=True)

Function to calculate drawdown levels in a timeseries

R{Series, DataFrame}

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

geometricbool

utilize geometric chaining (TRUE) or simple/arithmetic chaining (FALSE) to aggregate returns, by default True

risktools.find_drawdowns(R, geometric=True, *args)

Find the drawdowns and drawdown levels in a timeseries.

find_drawdowns() will find the starting period, the ending period, and the amount and length of the drawdown.

Often used with sort_drawdowns() to get the largest drawdowns.

drawdowns() will calculate the drawdown levels as percentages, for use in code{link{chart.Drawdown}}.

RSeries or DataFrame

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

geometricbool

utilize geometric chaining (TRUE) or simple/arithmetic chaining (FALSE) to aggregate returns, by default True

Nested dictionary with asset name(s) as the top level key(s). Nested below that as another dictionary are the following keys and values:

‘return’- numpy array of minimum of returns below the risk free rate of return (Rf) for each

trough. If returns are positive, array has 0 value

‘from’ - array index positiion of beginning of each trough or recovery period corresponding to each

element of ‘return’

‘trough’ - array index position of peak trough period corresponding to each

element of ‘return’. Returns beginning of recovery periods

‘to’ - array index positiion of end of each trough or recovery period corresponding to each

element of ‘return’

‘length’ - length of each trough period corresponding to each element of ‘return’ as given by

the difference in to and from index positions

‘peaktotrough’ - array index distance from the peak of each trough or recovery period from the

beginning of each trough or recovery period, corresponding to each element of ‘return’

‘recovery’ - array index distance from the peak of each trough or recovery period to the

end of each trough or recovery period, corresponding to each element of ‘return’

Bacon, C. Practical Portfolio Performance Measurement and Attribution. Wiley. 2004. p. 88

>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["SPY","AAPL"],  "yahoo", datetime(2000,1,1), datetime(2012,1,1))
>>> df = df.pct_change()
>>> df = df.asfreq('B')
>>> rs = find_drawdowns(df['Adj Close'])
>>> print(rs['SPY']['peaktotrough'])
risktools.fitOU(spread)

Parameter estimation for the Ornstein-Uhlenbeck process

spreadarray-like

OU process as a list or series to estimate parameters for

Dictionary of alpha, mu and theta

>>> import risktools as rt
>>> spread = rt.simOU(mu=5, theta=0.5, signma=0.2, T=5, dt=1/250)
>>> rt.fitOU(spread)
risktools.garch(df, out='data', scale=None, show_fig=True, forecast_horizon=1, **kwargs)

Computes annualised Garch(1,0,1) volatilities using arch package. Note that the RTL package uses a sGarch model, but there is no similiar implementation in python.

dfDataFrame

Wide dataframe with date column and single series (univariate).

outstr

“plotly” or “matplotlib” to return respective chart types. “data” to return data or “fit” for garch fit output. By default ‘data’

show_figbool

Only used if out is ‘matplotlib’ or ‘plotly’. If True, function will display plots as well as return their respective fig object

**kwargs

key-word parameters to pass tp arch_model. if none, sets p=1, o=0, q=1

out=’data’ returns a pandas df out=’fit’ returns an arch_model object from the package arch out=’matplotlib’ returns matplotlib figure and axes objects and displays the plot out=’plotly’ returns a plotly figure object and displays the plot

>>> import risktools as rt
>>> dflong = rt.data.open_data('dflong')
>>> dflong = dflong['CL01']
>>> df = rt.returns(df=dflong, ret_type="rel", period_return=1)
>>> df = rt.roll_adjust(df=df, commodity_name="cmewti", roll_type="Last_Trade")
>>> rt.garch(df, out="data")
>>> rt.garch(df, out="fit")
>>> rt.garch(df, out="plotly")
>>> rt.garch(df, out="matplotlib")
risktools.get_curves(username, password, feed='Crb_Futures_Price_Volume_And_Open_Interest', contract_roots=['CL', 'BG'], fields=['Open', 'High', 'Low', 'Close'], date=None)

function to get forward curves from the Morningstar data API. The following feeds are supported

  • Crb_Futures_Price_Volume_And_Open_Interest

  • CME_NymexFuturesIntraday_EOD

  • ICE_EuroFutures

  • ICE_EuroFutures_continuous

usernamestr

Morningstar API username

passwordstr

Morningstar API password

feedstr

API feed to get data from, by default “CME_NymexFutures_EOD”

contract_rootslist[tuple[str]]

either a string contract root code (i.e. “CL” for NYMEX WTI) or a list roots to return, by default [“CL”, “BG”].

datestr | datetime, optional

Date of curve to pull. By default None which causes function to return data for today.

risktools.get_eia_df(tables, key)

Function for download data from the US Government EIA and return it as a pandas dataframe/series

To get an api key, go to https://www.eia.gov/opendata/register.php To get table names, search via API explorer at https://www.eia.gov/opendata/qb.php

tablesList[Tuple[str]]

EIA series to return. Can be a list or tuple of tables as well.

keystr

EIA key.

pandas dataframe or series depending on the number of tables requested

>>> import risktools as rt
>>> rt.get_eia_df('PET.WDIIM_R20-Z00_2.W', key=eia_key)
risktools.get_ir_swap_curve(username, password, currency='USD', start_dt='2019-01-01', end_dt=None)

Extract historical interest rate swap data for Quantlib DiscountsCurve function using Morningstar and FRED data

username password currency start_dt end_dt

risktools.get_prices(username, password, feed='CME_NymexFutures_EOD', codes=['CL9Z', 'CL0F', 'CL0M'], start_dt='2019-01-01', end_dt=None, intraday=False)

function to get prices from the Morningstar data API. The following feeds are supported

  • CME_CbotFuturesEOD and CME_CbotFuturesEOD_continuous

  • CME_NymexFutures_EOD and CME_NymexFutures_EOD_continuous

  • CME_NymexOptions_EOD

  • CME_CmeFutures_EOD and CME_CmeFutures_EOD_continuous

  • CME_Comex_FuturesSettlement_EOD and CME_Comex_FuturesSettlement_EOD_continuous

  • LME_AskBidPrices_Delayed

  • SHFE_FuturesSettlement_RT

  • ICE_EuroFutures and ICE_EuroFutures_continuous

  • ICE_NybotCoffeeSugarCocoaFutures and ICE_NybotCoffeeSugarCocoaFutures_continuous

  • CME_STLCPC_Futures

  • CFTC_CommitmentsOfTradersCombined. Requires multiple keys. Separate them by a space e.g. “N10 06765A NYME 01”.

  • Morningstar_FX_Forwards. Requires multiple keys. Separate them by a space e.g. “USDCAD 2M”.

  • ERCOT_LmpsByResourceNodeAndElectricalBus

  • PJM_Rt_Hourly_Lmp

  • AESO_ForecastAndActualPoolPrice

usernamestr

Morningstar API username

passwordstr

Morningstar API password

feedstr

API feed to get data from, by default “CME_NymexFutures_EOD”

codeslist[tuple[str]]

either a string ticker code or a list of ticker codes or a futures contract type to return, by default [“CL9Z”, “CL0F”, “CL0M”].

start_dtstr | datetime, optional

earliest date to return data from, by default “2019-01-01”

end_dtstr | datetime, optional

lastest date to return data from, by default None. If None, the function return everything from start_dt forward

intradaybool

not implemented yet

risktools.infer_freq(x, multiplier=False)

Function to infer the frequency of a time series. Improvement over pandas.infer_freq as it can handle missing days/holidays. Note that for business days it will return ‘D’ vs ‘B’

xDataFrame | Series

Time series. Index MUST be a datetime index.

multiplierbool

If True, returns annualization factor for financial time series: 252 for daily/business day 52 for weekly 12 for monthly 4 for quarterly 1 for annual

str is multiplier = False

risktools.ir_df_us(quandl_key=None, ir_sens=0.01, date=None)

Extracts US Tresury Zero Rates using Quandl

quandl_keystr

Your Quandl key “yourkey” as a string, by default None. Optional as Quandl allows up to 50 calls per day for free

ir_sensfloat

Creates plus and minus IR sensitivity scenarios with specified shock value.

datestring

If date is not none, function will return ir curve for that date. By default None.

A pandas data frame of zero rates

>>> import risktools as rt
>>> ir = rt.ir_df_us()
risktools.npv(init_cost=- 375, C=50, cf_freq=0.25, F=250, T=2, disc_factors=None, break_even=False, be_yield=0.01)

Compute Net Present Value using discount factors from ir_df_us()

init_costfloat | int

Initial investment cost

Cfloat | int

Periodic cash flow

cf_freqfloat

Cash flow frequency in year fraction e.g. quarterly = 0.25

Ffloat | int

Final terminal value

Tfloat | int

Final maturity in years

disc_factorsDataFrame

Data frame of discount factors using ir_df_us() function.

break_evenbool

True when using a flat discount rate assumption.

be_yieldfloat | int

Set the flat IR rate when beak_even = True.

A python dictionary with elements ‘df’ as dataframe and ‘npv’ value as a float

>>> import risktools as rt
>>> ir = rt.ir_df_us(ir_sens=0.01)
>>> rt.npv(init_cost=-375, C=50, cf_freq=0.5, F=250, T=2, disc_factors=ir, break_even=True, be_yield=.0399)
risktools.omega_sharpe_ratio(R, MAR, *args)

Omega-Sharpe ratio of the return distribution

The Omega-Sharpe ratio is a conversion of the omega ratio to a ranking statistic in familiar form to the Sharpe ratio.

To calculate the Omega-Sharpe ration we subtract the target (or Minimum Acceptable Returns (MAR)) return from the portfolio return and we divide it by the opposite of the Downside Deviation.

\[OmegaSharpeRatio(R,MAR) = \frac{R_p - R_t}{ \sum^n_{t=1} \frac{max(R_t - R_i, 0)}{n} }\]

where \(n\) is the number of observations of the entire series

R{Series, DataFrame}

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

MAR{float, array_like[float]}

Minimum Acceptable Return, in the same periodicity as your returns

*argstuple

any other passthru parameters

float

>>> mar = 0.005
>>> print(omega_sharpe_ratio(portfolio_bacon, MAR))
risktools.prompt_beta(df, period='all', beta_type='all', output='chart')

Returns array/dataframe of betas for futures contract returns of a commodity with it’s front contract (i.e. next most expirying contract). For use with futures contracts (i.e. NYMEX WTI: CL01, CL02, CL03 and so forth) with standardized expiry periods.

Using the WTI example, the betas will represent the covariance of daily returns of CL02, CL03, CL04 with CL01. The covariance of CL01 with CL01 is also returned, but is always 1.

This function uses the single factor model (CAPM) beta. See the function CAPM_beta for more details

dfDataFrame

Wide dataframe with datetime index and multiple series columns for each futures contract. Always use continuous contracts for columns.

period[str | int | float]

Timeframe to use to calculate beta. “all” to use all data available or scalar number n to only use the last n periods/rows of data from the last, by default ‘all’. i.e. for WTI contracts (CL), 30 would be the last 30 days. Recommend running roll_adjust function prior to using prompt_beta to remove swings from contract expiry

beta_type{‘all’, ‘bull’, ‘bear’}, default ‘all’

Beta types to return

output{‘betas’, ‘chart’, ‘stats’}, default ‘chart’

Output type

chart

A plotly figure with the beta lines charted for ‘all’, ‘bear’ and ‘bull’ markets

betas

A dataframe of betas by contract order for ‘all’, ‘bear’ and ‘bull’ markets

stats

A scipy object from a least_squares fit of the betas by market type. Model used to fit betas was of the form: .. math:: {beta} = x0 * exp(x1*t) + x2 where t is the contract order (1, 2, 3 etc…, lower for expirying sooner)

chart, df of betas or stats

>>> import risktools as rt
>>> dfwide = rt.data.open_data('dfwide')
>>> col_mask = dfwide.columns[dfwide.columns.str.contains('CL')]
>>> dfwide = dfwide[col_mask]
>>> x = rt.returns(df=dfwide, ret_type="abs", period_return=1)
>>> x = rt.roll_adjust(df=x, commodity_name="cmewti", roll_type="Last_Trade")
>>> rt.prompt_beta(df=x, period="all", beta_type="all", output="chart")
>>> rt.prompt_beta(df=x, period="all", beta_type="all", output="betas")
>>> rt.prompt_beta(df=x, period="all", beta_type="all", output="stats")
>>> rt.prompt_beta(df=x, period=30, beta_type="all", output="plotly")
risktools.refineryLP(crude_inputs, product_outputs, return_all=False)

Refinery optimization LP model

crude_inputs : DataFrame

product_outputs : DataFrame

>>> import risktools as rt
>>> crudes = rt.data.open_data('ref_opt_inputs')
>>> products = rt.data.open_data('ref_opt_outputs')
>>> rt.refineryLP(crudes, products)
risktools.return_annualized(r, scale=None, geometric=True)

Based on the function Return.annualize from the R package PerformanceAnalytics by Peter Carl and Brian G. Peterson

Calculate an annualized return for comparing instruments with different length history

An average annualized return is convenient for comparing returns.

Annualized returns are useful for comparing two assets. To do so, you must scale your observations to an annual scale by raising the compound return to the number of periods in a year, and taking the root to the number of total observations:

\[prod(1+R_{a})^{\frac{scale}{n}}-1=\sqrt[n]{prod(1+R_{a})^{scale}}-1\]

where scale is the number of periods in a year, and n is the total number of periods for which you have observations.

For simple returns (geometric=FALSE), the formula is:

\[\overline{R_{a}} \cdot scale\]
rSeries or DataFrame

pandas Series with a datetime index with freq defined. Freq must be either ‘D’,’W’,’M’,’Q’ or ‘Y’

scaleint

number of periods in a year (daily scale = 252, monthly scale = 12, quarterly scale = 4). By default None. Note that if scale is None, the function will calculate a scale based on the index frequency. If however you wish to override this (becuase maybe there is no index freq), specify your own scale to use.

geometricbool

utilize geometric chaining (True) or simple/arithmetic chaining (False) to aggregate returns, by default True

floating point number if r is a Series, or pandas Series if r is a DataFrame

Bacon, Carl. Practical Portfolio Performance Measurement and Attribution. Wiley. 2004. p. 6

>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["SPY","AAPL"],  "yahoo", datetime(2000,1,1), datetime(2012,1,1))
>>> df = df.pct_change()
>>> df = df.asfreq('B')
>>> return_annualized(r=df[('Adj Close','SPY')], geometric=True)
>>> return_annualized(r=df[('Adj Close','SPY')], geometric=False)
>>> return_annualized(r=df['Adj Close'], geometric=True)
>>> return_annualized(r=df['Adj Close'], geometric=False)
risktools.return_cumulative(r, geometric=True)

Based on the function Return.annualize from the R package PerformanceAnalytics by Peter Carl and Brian G. Peterson

Calculate a compounded (geometric) cumulative return. Based om R’s PerformanceAnalytics

This is a useful function for calculating cumulative return over a period of time, say a calendar year. Can produce simple or geometric return.

product of all the individual period returns

\[(1+r_{1})(1+r_{2})(1+r_{3})\ldots(1+r_{n})-1=prod(1+R)-1\]
rSeries or DataFrame

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

geometricbool

utilize geometric chaining (TRUE) or simple/arithmetic chaining (FALSE) to aggregate returns, by default True

floating point number if r is a Series, or pandas Series if r is a DataFrame

>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> spy = data.DataReader("SPY",  "yahoo", datetime(2000,1,1), datetime(2012,1,1))
>>> spy = spy.pct_change()
>>> return_cumulative(spy['Adj Close'])
>>> return_cumulative(spy['Adj Close'],geometric=FALSE)
risktools.return_excess(R, Rf=0)

Calculates the returns of an asset in excess of the given risk free rate

Calculates the returns of an asset in excess of the given “risk free rate” for the period.

Ideally, your risk free rate will be for each period you have returns observations, but a single average return for the period will work too.

Mean of the period return minus the period risk free rate

\[\overline{(R_{a}-R_{f})}\]

OR

mean of the period returns minus a single numeric risk free rate

\[\overline{R_{a}}-R_{f}\]

Note that while we have, in keeping with common academic usage, assumed that the second parameter will be a risk free rate, you may also use any other timeseries as the second argument. A common alteration would be to use a benchmark to produce excess returns over a specific benchmark, as demonstrated in the examples below.

RSeries or DataFrame

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

Rffloat

risk free rate, in same period as your returns, or as a single digit average

Bacon, Carl. emph{Practical Portfolio Performance Measurement and Attribution}. Wiley. 2004. p. 47-52

data(managers) head(Return.excess(managers[,1,drop=FALSE], managers[,10,drop=FALSE])) head(Return.excess(managers[,1,drop=FALSE], .04/12)) head(Return.excess(managers[,1:6], managers[,10,drop=FALSE])) head(Return.excess(managers[,1,drop=FALSE], managers[,8,drop=FALSE]))

risktools.returns(df, ret_type='abs', period_return=1, spread=False)

Computes periodic returns from a dataframe ordered by date

dfSeries or DataFrame

If pandas series, series must have a single datetime index or a multi-index in the same of (‘asset name’,’date’). Values must be asset prices If pandas dataframe, dataframe must have a single datetime index with asset prices as columns

ret_typestr

“abs” for absolute, “rel” for relative, or “log” for log returns. By default “abs”

period_returnint

Number of rows over which to compute returns. By default 1

spreadbool

True if you want to spread into a wide dataframe. By default False

A pandas series of returns.

>>> import risktools as rt
>>> rt.returns(df = rt.data.open_data('dflong'), ret_type = "rel", period_return = 1, spread = True)
>>> rt.returns(df = rt.data.open_data('dflong'), ret_type = "rel", period_return = 1, spread = False)
risktools.roll_adjust(df, commodity_name='cmewti', roll_type='Last_Trade', roll_sch=None, *args)

Returns a pandas series adjusted for contract roll. The methodology used to adjust returns is to remove the daily returns on the day after expiry and for prices to adjust historical rolling front month contracts by the size of the roll at each expiry. This is conducive to quantitative trading strategies as it reflects the PL of a financial trader.

Note that this will apply a single expiry schedule to all assets passed to this function. To apply different roll schedules by asset type, perform a separate function call.

dfSeries | DataFrame

pandas series or dataframe with a with a datetime index and which columns are asset prices or with a dataframe with a multi-index in the shape (‘asset name’,’date’)

commodity_namestr

Name of commodity in expiry_table. See example below for values.

roll_typestr

Type of contract roll: “Last_Trade” or “First_Notice”. By default “Last_Trade”

roll_schSeries

For future capability. Optional

*args: Other parms to pass to function

Roll-adjusted pandas series object of returns with datetime index or multi-index with the shape (‘asset name’,’date’)

>>> import risktools as rt
>>> dflong = rt.data.open_data('dflong')
>>> rt.data.open_data('expiry_table').cmdty.unique() # for list of commodity names
>>> ret = rt.returns(df=dflong, ret_type="abs", period_return=1, spread=True)
>>> ret = ret.iloc[:,0]
>>> rt.roll_adjust(df=ret, commodity_name="cmewti", roll_type="Last_Trade")
risktools.sd_annualized(x, scale=None, *args)

calculate a multiperiod or annualized Standard Deviation

Standard Deviation of a set of observations eqn{R_{a}} is given by:

deqn{sigma = variance(R_{a}) , std=sqrt{sigma} }{std = sqrt(var(R))}

It should follow that the variance is not a linear function of the number of observations. To determine possible variance over multiple periods, it wouldn’t make sense to multiply the single-period variance by the total number of periods: this could quickly lead to an absurd result where total variance (or risk) was greater than 100%. It follows then that the total variance needs to demonstrate a decreasing period-to-period increase as the number of periods increases. Put another way, the increase in incremental variance per additional period needs to decrease with some relationship to the number of periods. The standard accepted practice for doing this is to apply the inverse square law. To normalize standard deviation across multiple periods, we multiply by the square root of the number of periods we wish to calculate over. To annualize standard deviation, we multiply by the square root of the number of periods per year.

deqn{sqrt{sigma}cdotsqrt{periods}}

Note that any multiperiod or annualized number should be viewed with suspicion if the number of observations is small.

xSeries or DataFrame

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

scaleint (optional)

number of periods in a year (daily scale = 252, monthly scale = 12, quarterly scale = 4). By default None. Note that if scale is None, the function will calculate a scale based on the index frequency. If however you wish to override this (becuase maybe there is no index freq), specify your own scale to use.

*args

any other passthru parameters

floating point number if r is a Series, or pandas Series if r is a DataFrame

>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["SPY","AAPL"],  "yahoo", datetime(2000,1,1), datetime(2012,1,1))
>>> df = df.pct_change()
>>> df = df.asfreq('B')
>>> sd_annualized(x=df[('Adj Close','SPY')])
>>> sd_annualized(x=df['Adj Close'])
risktools.sharpe_ratio_annualized(R, Rf=0, scale=None, geometric=True)

calculate annualized Sharpe Ratio

The Sharpe Ratio is a risk-adjusted measure of return that uses standard deviation to represent risk.

The Sharpe ratio is simply the return per unit of risk (represented by variance). The higher the Sharpe ratio, the better the combined performance of “risk” and return.

This function annualizes the number based on the scale parameter.

\[\frac{\sqrt[n]{prod(1+R_{a})^{scale}}-1}{\sqrt{scale}\cdot\sqrt{\sigma}}\]

Using an annualized Sharpe Ratio is useful for comparison of multiple return streams. The annualized Sharpe ratio is computed by dividing the annualized mean monthly excess return by the annualized monthly standard deviation of excess return.

William Sharpe now recommends Information Ratio preferentially to the original Sharpe Ratio.

Rarray_like

an xts, vector, matrix, data frame, timeSeries or zoo object of asset returns

Rffloat

risk free rate, in same period as your returns. By default 0

scaleint

number of periods in a year (daily scale = 252, monthly scale = 12, quarterly scale = 4). By default None

geometricbool

utilize geometric chaining (True) or simple/arithmetic chaining (False) to aggregate returns, default True

see also code{link{SharpeRatio}} cr code{link{InformationRatio}} cr code{link{TrackingError}} cr code{link{ActivePremium}} cr code{link{SortinoRatio}}

Sharpe, W.F. The Sharpe Ratio,emph{Journal of Portfolio Management},Fall 1994, 49-58.

>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["SPY","AAPL"],  "yahoo", datetime(2000,1,1), datetime(2012,1,1))
>>> df = df.pct_change()
>>> df = df.asfreq('B')
risktools.simGBM(s0=10, drift=0, sigma=0.2, T=1, dt=0.08333333333333333)

Simulates a Geometric Brownian Motion process

s0 : spot price at time = 0 drift : drift % sigma : standard deviation T : maturity in years dt : time step in period e.g. 1/250 = 1 business day

A list of simulated values

>>> import risktools as rt
>>> rt.simGBM(s0=5, drift=0, sigma=0.2, T=2, dt=0.25)
risktools.simOU(s0=5, mu=4, theta=2, sigma=1, T=1, dt=0.003968253968253968)

Function for calculating an Ornstein-Uhlenbeck Mean Reversion stochastic process (random walk)

From Wikipedia:

https://en.wikipedia.org/wiki/Ornstein-Uhlenbeck_process

The process is a stationary Gauss–Markov process, which means that it is a Gaussian process, a Markov process, and is temporally homogeneous. In fact, it is the only nontrivial process that satisfies these three conditions, up to allowing linear transformations of the space and time variables. Over time, the process tends to drift towards its mean function: such a process is called mean-reverting.

s0float

Starting value for mean reverting random walk at time = 0

mufloat, int or pandas Series

Mean that the function will revert to

thetafloat

Mean reversion rate, higher number means it will revert slower

sigmafloat

Annualized volatility or standard deviation. To calculate, take daily volatility and multiply by sqrt(T/dt)

Tfloat or int

Period length in years (i.e. 0.25 for 3 months)

dtfloat

Time step size in fractions of a year. So a day would be 1/252, where 252 is the number of business days in a year

A numpy array of simulated values

>>> import risktools as rt
>>> rt.simOU()
risktools.simOUJ(s0=5, mu=5, theta=0.5, sigma=0.2, jump_prob=0.05, jump_avgsize=3, jump_stdv=0.05, T=1, dt=0.08333333333333333)

Function for calculating an Ornstein-Uhlenbeck Mean Reversion stochastic process (random walk) with Jump

From Wikipedia:

https://en.wikipedia.org/wiki/Ornstein-Uhlenbeck_process

The process is a stationary Gauss–Markov process, which means that it is a Gaussian process, a Markov process, and is temporally homogeneous. In fact, it is the only nontrivial process that satisfies these three conditions, up to allowing linear transformations of the space and time variables. Over time, the process tends to drift towards its mean function: such a process is called mean-reverting.

s0float

Starting value for mean reverting random walk at time = 0

mufloat, int or pandas Series

Mean that the function will revert to. Can be either a scalar value (i.e. 5) or a pandas series for a time dependent mean. If array-like, it must be the same length as T/dt (i.e. the number of periods)

thetafloat

Mean reversion rate, higher number means it will revert slower

sigmafloat

Annualized volatility or standard deviation. To calculate, take daily volatility and multiply by sqrt(T/dt)

jump_probfloat

Probablity of jumps

jump_avgsizefloat

Average size of jumps

jump_stdvfloat

Standard deviation of average jump size

Tfloat or int

Period length in years (i.e. 0.25 for 3 months)

dtfloat

Time step size in fractions of a year. So a day would be 1/252, where 252 is the number of business days in a year

simsint

Number of simulations to run

A pandas dataframe with the time steps as rows and the number of simulations as columns

>>> import risktools as rt
>>> rt.simOUJ()
risktools.simOUJ_arr(s0=5, mu=5, theta=0.5, sigma=0.2, jump_prob=0.05, jump_avgsize=3, jump_stdv=0.05, T=1, dt=0.08333333333333333, sims=1000)

Function for calculating an Ornstein-Uhlenbeck Jump Mean Reversion stochastic process (random walk) with multiple simulations

From Wikipedia:

https://en.wikipedia.org/wiki/Ornstein-Uhlenbeck_process

The process is a stationary Gauss–Markov process, which means that it is a Gaussian process, a Markov process, and is temporally homogeneous. In fact, it is the only nontrivial process that satisfies these three conditions, up to allowing linear transformations of the space and time variables. Over time, the process tends to drift towards its mean function: such a process is called mean-reverting.

s0float

Starting value for mean reverting random walk at time = 0

mufloat, int or pandas Series

Mean that the function will revert to. Can be either a scalar value (i.e. 5) or a pandas series for a time dependent mean. If array-like, it must be the same length as T/dt (i.e. the number of periods)

thetafloat

Mean reversion rate, higher number means it will revert slower

sigmafloat

Annualized volatility or standard deviation. To calculate, take daily volatility and multiply by sqrt(T/dt)

jump_probfloat

Probablity of jumps

jump_avgsizefloat

Average size of jumps

jump_stdvfloat

Standard deviation of average jump size

Tfloat or int

Period length in years (i.e. 0.25 for 3 months)

dtfloat

Time step size in fractions of a year. So a day would be 1/252, where 252 is the number of business days in a year

simsint

Number of simulations to run

A pandas dataframe with the time steps as rows and the number of simulations as columns

>>> import risktools as rt
>>> rt.simOUJ_arr()
risktools.simOU_arr(s0=5, mu=4, theta=2, sigma=1, T=1, dt=0.003968253968253968, sims=1000)

Function for calculating an Ornstein-Uhlenbeck Mean Reversion stochastic process (random walk) with multiple simulations

From Wikipedia:

https://en.wikipedia.org/wiki/Ornstein-Uhlenbeck_process

The process is a stationary Gauss–Markov process, which means that it is a Gaussian process, a Markov process, and is temporally homogeneous. In fact, it is the only nontrivial process that satisfies these three conditions, up to allowing linear transformations of the space and time variables. Over time, the process tends to drift towards its mean function: such a process is called mean-reverting.

s0float

Starting value for mean reverting random walk at time = 0

mufloat, int or pandas Series

Mean that the function will revert to. Can be either a scalar value (i.e. 5) or a pandas series for a time dependent mean. If array-like, it must be the same length as T/dt (i.e. the number of periods)

thetafloat

Mean reversion rate, higher number means it will revert slower

sigmafloat

Annualized volatility or standard deviation. To calculate, take daily volatility and multiply by sqrt(T/dt)

Tfloat or int

Period length in years (i.e. 0.25 for 3 months)

dtfloat

Time step size in fractions of a year. So a day would be 1/252, where 252 is the number of business days in a year

simsint

Number of simulations to run

A pandas dataframe with the time steps as rows and the number of simulations as columns

>>> import risktools as rt
>>> rt.simOU_arr()
risktools.stl_decomposition(df, output='chart', period=None, seasonal=7, seasonal_deg=1, resample_freq='M', **kwargs)

Provides a summary of returns distribution using the statsmodels.tsa.seasonal.STL class. Resamples all data to prior to STL if

dfSeries

A pandas series (univariate) with a datetime index.

outputstr

“chart” to see output as a graph, “data” for results as a list. By default “chart”

seasonalint, optional

Length of the seasonal smoother. Must be an odd integer, and should normally be >= 7 (default).

seasonal_degint, optional

Degree of seasonal LOESS. 0 (constant) or 1 (constant and trend). By default 1

resample_freqstr

Resampling frequency to use in pandas resample function. Set to None to not resample

**kwargs :

Other parms

season - The length of the seasonal smoother. Must be odd.

trend - The length of the trend smoother, usually around 150% of season. Must be odd and larger than season.

low_pass - The length of the low-pass estimation window, usually the smallest odd number larger than the periodicity of the data.

a chart or statsmodels.tsa.seasonal.DecomposeResult object of results

>>> import risktools as rt
>>> df = rt.data.open_data('dflong')
>>> df = df['CL01']
>>> rt.stl_decomposition(df, output="chart", seasonal=13, seasonal_deg=1, resample_freq='M')
>>> rt.stl_decomposition(df, output="data", seasonal=13, seasonal_deg=1, resample_freq='M')
risktools.swap_com(df, futures_names, start_dt, end_dt, cmdty, exchange)

Function to calculate commodity swap pricing from futures contract exchange settlements of two contracts. Mostly used when the contract expires mid-month to work out the calendar month average

dfDataFrame

Wide dataframe of futures prices

futures_namesList[Tuple[str]]

2 element List or tuple of futures contract names in order of expiry (i.e. [first expirying contract, second expirying contract])

start_dtstr | datetime

A string in the format of ‘YYYY-mm-dd’ or a datetime object

end_dtstr | datetime

A string in the format of ‘YYYY-mm-dd’ or a datetime object

cmdtystr

name of expiry contract type as specified in the expiry_table of this package. See risktools.data.open_data(‘expiry_table’)[‘cmdty’]

exchange[‘nymex’,’ice’]

Name of exchange. Only ‘nymex’ and ‘ice’ supported. Used to filter the dataframe risktools.data.open_data(‘holidaysOil’)

a dataframe of swap prices

>>> df = rt.get_prices(up['m*']['user'], up['m*']['pass'], codes=['CL0M','CL0N','CL0Q'], start_dt='2019-08-26')
>>> df = df.settlement_price.unstack(level=0)
>>> rt.swap_com(df=df, futures_names=["CL0M","CL0N"], start_dt="2020-05-01", end_dt="2020-05-30", cmdty="cmewti", exchange="nymex")
risktools.swap_fut_weight(month, contract='cmewti', exchange='nymex', output='first_fut_weight')

Function used to calculate the calendar month average price of a futures curve. Some futures curves such as NYMEX WTI expires mid-month (i.e. 2020-09-22) but some products are priced as differentials to the calendar month average (CMA) price of the contracts. To calculate the CMA, up need the contract that’s active for the first part of the month, the contract that’s active for the later half as well as the weighting to apply to both. This function is designed to return the weights for contracts 1 and 2 as well as the weights

monthstr | datetime

First calendar day of the month in YYYY-MM-DD

contractstr

Exchange code in data.open_data(“holidaysOil”). Currently only “nymex” and “ice” supported. By default “cmewti”

exchangestr

Contract code in data.open_data(“expiry_table”). By default “nymex”

outputstr

“num_days_fut1” to get the number of days from the beginning of the month up to and including the expiry date. “num_days_fut2” to get the number of days from the expiry date to month end. “first_fut_weight” the weight to assign to the futures contract for “month” as a ratio of the number of days before expiry (i.e. include in ). By default “first_fut_weight”

If first_fut_weight as dataframe, if not then an integer

>>> import risktools as rt
>>> rt.swap_fut_weight(month="2020-09-01", contract="cmewti", exchange="nymex", output="first_fut_weight")
risktools.swap_info(username, password, date=None, tickers=['CL', 'CL_001_Month'], feeds=['Crb_Futures_Price_Volume_And_Open_Interest', 'CME_NymexFutures_EOD_continuous'], exchange='nymex', contract='cmewti', output='all')

Returns dataframe required to price a WTI averaging instrument based on first line settlements.

usernamestr

Morningstar user name as character - sourced locally in examples.

passwordstr

Morningstar user password as character - sourced locally in examples.

datestr | datetime

Date as of which you want to extract daily settlement and forward values. By default None

tickersstr | iterable[str]

Morningstar tickers for get_curve() and get_prices() functions

feedsstr | iterable[str]

Feeds for Morningstar get_curve() and get_prices() functions. Must be in same order as tickers parameter

exchangestr

Exchange code in holidaysOil from risktools.data.open_data function. Defaults to “nymex”.

contractstr

Contract code in expiry_table. from risktools.data.open_data function. See risktools.data.open_date(“expiry_table”).cmdty.unique() for options.

output :str

“chart” for chart, “dataframe” for dataframe or “all” dataframe and chart

Plot, dataframe or a dict of data frame and plot if output = “all”.

>>> import risktools as rt
>>> feeds = ["Crb_Futures_Price_Volume_And_Open_Interest",
        "CME_NymexFutures_EOD_continuous"]
>>> ticker = ["CL","CL_001_Month"]
>>> swap_info(username, password, date="2020-05-06", tickers=tickers, feeds=feeds, contract="cmewti", exchange="nymex",
        output = "all")
risktools.swap_irs(trade_date=None, eff_date=None, mat_date=None, notional=1000000, pay_rec='rec', fixed_rate=0.05, float_curve=None, reset_freq='Q', disc_curve=None, days_in_year=360, convention='act', bus_calendar='NY', output='price')

Commodity swap pricing from exchange settlement

trade_dateTimestamp | str

The date of the trade. If None, defaults to today(). By default None.

eff_dateTimestamp | str

The effective date of the swap. If None, defaults to trade_date + 2 days. By default None.

mat_dateTimestamp | str

The maturity date of the swap. If None, defaults to eff_date + 2 years.

notionallong int

Numeric value of notional. Defaults to 1,000,000.

pay_recstr

“pay” for pyement (positive pv) or “rec” for receivables (negative pv).

fixed_ratefloat

fixed interest rate. Defaults to 0.05.

float_curveDataFrame | Dict

DataFrame of interest rate curves with columns ‘times’ and ‘discounts’. If None, defaults to rt.data.open_data(“usSwapCurves”) which is a dictionary based on the R object DiscountCurve. Column times is year fractions going forward in time. So today is 0, tomorrow is 1/365, a year from today is 1 etc…

reset_freqstr

Pandas/datetime Timestamp frequency (allowable values are ‘M’, ‘Q’, ‘6M’, or ‘Y’)

disc_curveDataFrame | Dict

DataFrame of interest rate curves with columns ‘times’ and ‘discounts’. If None, defaults to rt.data.open_data(“usSwapCurves”) which is a dictionary based on the R object DiscountCurve. Column times is year fractions going forward in time. So today is 0, tomorrow is 1/365, a year from today is 1 etc…

days_in_yearint

360 or 365

conventionlist

List of convention e.g. [“act”,360], [30,360],…

bus_calendarstr

Banking day calendar. Not implemented.

outputstr

“price” for swap price or “all” for price, cash flow data frame, duration.

returns present value as a scalar if output==’price. Otherwise returns dictionary with swap price, cash flow data frame and duration

>>> import risktools as rt
>>> usSwapCurves = rt.data.open_data('usSwapCurves')
>>> rt.swap_irs(trade_date="2020-01-04", eff_date="2020-01-06", mat_date="2022-01-06", notional=1000000, pay_rec = "rec", fixed_rate=0.05, float_curve=usSwapCurves, reset_freq='Q', disc_curve=usSwapCurves, days_in_year=360, convention="act", bus_calendar="NY", output = "all")
risktools.timing_ratio(Ra, Rb, Rf=0)

The function timing_ratio may help assess whether the manager is a good timer of asset allocation decisions. The ratio is best when greater than one in a rising market and less than one in a falling market.

Raarray-like or DataFrame

Array-like or DataFrame with datetime index of asset returns to be tested vs benchmark

Rbarray-like

Benchmark returns to use to test Ra

Rfarray-like | float

risk free rate, in same period as your returns, or as a single digit average

If Ra is array-like, function returns beta as a scalar. If Ra is a DataFrame, it will return a series indexed with asset names from df columns

\[TimingRatio = \frac{\beta^{+}}{\beta^{-}}\]
>>> import risktools as rt
>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["XOM","AAPL","SPY"],  "yahoo", datetime(2010,1,1), datetime(2017,12,31))
>>> df = df.pct_change()['Adj Close']
>>> df = df.asfreq('B')
>>> rt.timing_ratio(df[['XOM','AAPL']], df['SPY'], Rf=0)
risktools.trade_stats(R, Rf=0)

Compute list of risk reward metrics

RSeries or DataFrame

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

Rffloat

risk free rate, in same period as your returns, or as a single digit average

Dictionary with cummulative returns, annual returns, Annualized Sharpe ratio, Omega Sharpe ratio, Win &, % in the market, and drawdown specs

>>> from pandas_datareader import data
>>> df = data.DataReader(["SPY","AAPL"],  "yahoo", '2000-01-01', '2012-01-01')
>>> df = df.pct_change()
>>> df = df.asfreq('B')
>>> rt.trade_stats(df[('Adj Close','SPY')])
risktools.upside_risk(R, MAR=0, method='full', stat='risk')

upside risk, variance and potential of the return distribution

Upside Risk is the similar of semideviation taking the return above the Minimum Acceptable Return instead of using the mean return or zero . To calculate it, we take the subset of returns that are more than the target (or Minimum Acceptable Returns (MAR)) returns and take the differences of those to the target. We sum the squares and divide by the total number of returns and return the square root.

R{Series, DataFrame}

pandas Series or DataFrame with a datetime index. If DataFrame, function will calculate cummmulative returns on each column

MARint

Minimum Acceptable Return, in the same periodicity as your returns

method{‘full’,’subset’}, default ‘full’

Either “full” or “subset”, indicating whether to use the length of the full series or the length of the subset of the series below the MAR as the denominator, defaults to “full”

stat{“risk”, “variance”, “potential”}, default ‘risk’

one of “risk”, “variance” or “potential” indicating whether to return the Upside risk, variance or potential. By default, ‘risk’

float

Equations:

\[ \begin{align}\begin{aligned}UpsideRisk(R, MAR) = \sqrt{\sum_{n}^{t=1} \frac{max[(R_{t} - MAR), 0]^2}{n}}\\UpsideVariance(R, MAR) = \sum^{n}_{t=1} \frac{max[(R_{t} - MAR), 0]^2}{n}\\UpsidePotential(R, MAR) = \sum^{n}_{t=1} \frac{max[(R_{t} - MAR), 0]} {n}\end{aligned}\end{align} \]

where n is either the number of observations of the entire series or the number of observations in the subset of the series falling below the MAR.

>>> from pandas_datareader import data, wb
>>> from datetime import datetime
>>> df = data.DataReader(["SPY","AAPL"],  "yahoo", datetime(2000,1,1), datetime(2012,1,1))
>>> df = df.pct_change()
>>> df = df.asfreq('B')
>>> print(upside_risk(df['Adj Close'], MAR=0))
>>> print(upside_risk(df[('Adj Close','SPY')], MAR=0))
>>> print(upside_risk(df['Adj Close'], MAR=0, stat='variance'))
>>> print(upside_risk(df['Adj Close'], MAR=0, stat='potential'))

risktools data submodule

risktools.data.get_gis(url='https://www.eia.gov/maps/map_data/CrudeOil_Pipelines_US_EIA.zip')

Returns a SpatialPointsDataFrame from a shapefile URL. Examples with EIA and Government of Alberta

US Energy Information Agency:

Alberta Oil Sands, Petroleum and Natural Gas

urlstr

URL of the zipped shapefile

Returns geopandas object

>>> import risktools as rt
>>> df = rt.data.get_gis("https://www.eia.gov/maps/map_data/CrudeOil_Pipelines_US_EIA.zip")
risktools.data.get_names()

return valid names for the open_data() function.

List of strings

>>> import risktools as rt
>>> rt.get_names()
risktools.data.open_data(nm)

Function used to return built-in datasets from risktools. To get a list of valid datasets, use the get_names() function.

nmstr

Name of dataset to return

Varies by data requests

>>> import risktools as rt
>>> rt.open_data('cancrudeassays')