Universal portfolio¶
The concept of “Universal” portfolio was introduced by Thomas M. Cover in 1996. It has its roots in Information Theory.
Let us assume a long-only portfolio with \(M\) components. Then, the portfolio weights, \(b\), is a set of non-negative numbers belonging to the M-simplex \(b^T \cdot b = 1\) and \(b_{i} \geq 0\) for \(\forall i \in 1,\cdots,M\).
Let \(S_n = \Pi_{k=1}^n b_k^T \cdot x_k\) be the portfolio wealth after \(n\) reinvestments. Here \(b_k\) vector is the set of portfolio weights during the \(k\)-th reinvestment period, and \(x_k\) is a vector of ratios between the asset’s closing prices at the end and at the beginning of the \(k\)-th reinvestment period (i.e., \(x_{k;i} = P_{k+1;i} / P_{k;i}\), where \(P_{k;i}\) is the \(i\)-th asset closing price in day \(k\)).
Moreover, let \({\hat S}_n\) be the wealth of the BCWP (Best Constant Weighted Portfolio). The BCWP weights are computed in hindsight, after the last settlement of reinvestment period \(n\). Therefore, it is an ideal benchmark, unknown at investment time. It is known only after the market’s final settlement.
A portfolio strategy (i.e., the set of weights \(\{b_k\}_{k=1,\cdots,\infty }\)) is called “Universal portfolio” if
Cover’s 1996 portfolio weights are defined by the following non-anticipating sequence of weights,
where, \({\cal B}_M\) is the M-simplex \(b^T \cdot b = 1\) and \(b_{i} \geq 0\). The initial values, \(b_1\), are set to \(1/n\) (equal weighted). Cover’s 1996 portfolio is a Universal portfolio.
azapy implements a Monte Carlo estimator to evaluate the integrals in the expression of the weights. The underlining random generators for \(b\) vectors on the M-simplex \({\cal B}_M\) are based on the Dirichlet (for arbitrary \(\alpha\)-parameters) as well as a on the Uniform, equivalent to a Flat Dirichlet (all \(\alpha\) set to \(1\)), distributions. The user is allowed to choose between various underling random vector generators.
Optionally, the implementation provides the antithetic variance reduction generated using all the permutations of \(b\) components. Note that in this case the total number of Monte Carlo simulations will increase by a factor equal to the factorial of the number of portfolio components (e.g., if the portfolio components is 7, then the effective number of MC simulations is multiplied by 5040). This feature should be used with care, only for portfolios with a relatively small number of components.
There are 2 support classes:
UniversalEngine: computes the portfolio weights and performs in-sample analysis,
Port_Universal : performs portfolio backtesting, out-of-sample analysis.
Note, the UniversalEngine class cannot be imbedded into the ModelPipeline mechanism.
UniversalEngine class¶
- class azapy.Engines.UniversalEngine.UniversalEngine(mktdata=None, colname='adjusted', freq='M', name='Universal', schedule=None, sdate=None, edate='today', noffset=0, fixoffset=0, hlength=12, dirichlet_alpha=None, variance_reduction=True, nr_batches=16, mc_paths=100, mc_seed=42, verbose=False)¶
Bases:
_RiskEngine
Cover’s (1996) Universal Portfolio
- Attributes
status : int - computation status (0 - success, any other value indicates an error)
ww : pandas.DataFrame - portfolio weights at each rebalancing date
name : str - portfolio name
Methods
Returns the BCWP (Best Constant Weighted Portfolio) weights.
getPositions
([nshares, cash, ww, nsh_round, ...])Computes the rebalanced number of shares.
getWeights
([mktdata, dirichlet_alpha, ...])Computes the portfolio weights for each fixing date.
set_mktdata
(mktdata[, colname, schedule, ...])Sets historical market data.
set_rrate
(rrate)Sets portfolio components historical rates of return in the format "date", "symbol1", "symbol2", etc.
- __init__(mktdata=None, colname='adjusted', freq='M', name='Universal', schedule=None, sdate=None, edate='today', noffset=0, fixoffset=0, hlength=12, dirichlet_alpha=None, variance_reduction=True, nr_batches=16, mc_paths=100, mc_seed=42, verbose=False)¶
Constructor
- Parameters:
- mktdatapandas.DataFrame, optional
Historic daily market data for portfolio components in the format returned by azapy.mktData function. The default is None.
- colnamestr, optional
Name of the price column from mktdata used in the weight’s calibration. The default is ‘adjusted’.
- freqstr, optional
Rate of return horizon. It could be ‘Q’ for a quarter or ‘M’ for a month. The default is ‘M’.
- namestr, optional
Portfolio name. The default value is ‘Universal’.
- scheduleazapy.schedule_simple, optional
External schedule of fixing dates. If it is None then the fixing schedule will be generated internally. The default is None.
- fixoffsetint, optional
Fixing date as number of business days offset relative to the rebalance date. Must be <=0. It is relevant only is schedule`=`None. The default is -1.
- hlengthfloat, optional
History length in number of years used for calibration. A fractional number will be rounded to an integer number of months. For this model, the value of hlength must be as large is possible given the market data length and computational resources. The default is 12 years.
- dirichlet_alphalist, optional
List of Dirichlet alpha coefficients (to be used by the Dirichlet random number generator). The length must be the same with the number of symbols in the portfolio. A possible example is alpha = [0.5] * n where n is the number of symbols in the portfolio. If alpha is set to None then a uniform generator in the n-simplex sum_{k=1}^n x_k = 1 with x_k >= 0 is assumed (it is equivalent to Dirichlet for alpha=[1] * n). The default is None.
- variance_reductionBoolean, optional
If it is set to True, then the antithetic variance reduction generated by the permutations of the portfolio components is deployed. The effective number of Monte Carlo simulations will be multiplied by the factorial of the number of symbols in the portfolio. The default is True.
- nr_batchespositive int, optional
The number of a Monte Carlo batches. Since the computation is multithreaded, a good value could be a multiple of the number of cores. The default is 16.
- mc_pathspositive int, optional
Number of simulations per Monte Carlo batch. If variance_reduction is set to True then the total number of simulation will be multiplied by M! where M is the number of portfolio components. For example, 7 assets (7! = 5040), 16 baches, of 100 paths will lead to 5040 * 16 * 100 = 8,064,000 numbers of MC simulation paths . The default is 100.
- mc_seednon negative int, optional
Random number generator seed. If it has a value other than None the random generator will be reseeded. The default value is 42.
- verboseBoolean, optional
If it is set to True, then various computation messages (meant as warnings) will be printed. The default is False.
- mc_seedint, optional
Random number generator seed. The default is 42.
- Returns:
- The object.
- benchmark()¶
Returns the BCWP (Best Constant Weighted Portfolio) weights.
- Returns:
- pandas.DataFrame
The BCWP weights. Each row represents the weights of a BCWP with maturity given by the index value.
- getPositions(nshares=None, cash=0.0, ww=None, nsh_round=True, verbose=True)¶
Computes the rebalanced number of shares.
- Parameters:
- nsharespanda.Series, optional
Initial number of shares per portfolio component. A missing component entry will be considered 0. A None value assumes that all components entries are 0. The name of the components must be present in the mrkdata. The default is None.
- cashfloat, optional
Additional cash to be added to the capital. A negative entry assumes a reduction in the total capital available for rebalance. The total capital cannot be < 0. The default is 0.
- wwpanda.Series, optional
External overwrite portfolio weights. If it not set to None these weights will overwrite the calibration results. The default is None.
- nsh_roundBoolean, optional
If it is True the invested numbers of shares are round to the nearest integer and the residual cash capital (positive or negative) is carried to the next reinvestment cycle. A value of False assumes investments with fractional number of shares (no rounding). The default is True.
- verboseBoolean, optional
Is it set to True the function prints the closing prices date. The default is True.
- Returns:
- `pandas.DataFrame`the rolling information.
- Columns:
- ‘old_nsh’ :
initial number of shares per portfolio component and the additional cash. These are input values.
- ‘new_nsh’ :
the new number of shares per component plus the residual cash (due to the rounding to an integer number of shares). A negative entry means that the investor needs to add more cash to cover for the roundup shortfall. It has a small value.
- ‘diff_nsh’ :
number of shares (buy/sale) needed to rebalance the portfolio.
- ‘weights’ :
portfolio weights used for rebalancing. The cash entry is the new portfolio value (invested capital).
- ‘prices’ :
the share prices used for rebalance evaluations.
Note: Since the prices are closing prices, the rebalance can be computed after the market close and before the trading execution (next day). Additional cash slippage may occur due to share price differential between the previous day closing and execution time.
- getWeights(mktdata=None, dirichlet_alpha=None, variance_reduction=None, nr_batches=None, mc_paths=None, mc_seed=None, finalonly=True, verbose=False)¶
Computes the portfolio weights for each fixing date. In the last entry (row) are the portfolio weights corresponding to the fixing_date.
- Parameters:
- mktdatapandas.DataFrame, optional
The portfolio components historical, prices or rates of return, see ‘pclose’ definition below. If it is not None, it will overwrite the set of historical rates of return computed in the constructor from ‘mktdata’. The default is None.
- dirichlet_alphalist, optional
List of Dirichlet alpha coefficients (to be used by the Dirichlet random number generator). The length must be the same with the number of symbols in the portfolio. A possible example is alpha = [0.5] * n where n is the number of symbols in the portfolio. If alpha is set to None then a uniform generator in the n-simplex sum_{k=1}^n x_k = 1 with x_k >= 0 is assumed (it is equivalent to Dirichlet for alpha=[1] * n). The default is None.
- variance_reductionBoolean, optional
If it is set to True, then the antithetic variance reduction generated by the permutations of the portfolio components is deployed. The effective number of Monte Carlo simulations will be multiplied by the factorial of the number of symbols in the portfolio. The default is True.
- nr_batchespositive int, optional
The number of a Monte Carlo batches. Since the computation is multithreaded, a good value could be a multiple of the number of cores. The default is 16.
- mc_pathspositive int, optional
Number of simulations per Monte Carlo batch. If variance_reduction is set to True then the total number of simulation will be multiplied by M! where M is the number of portfolio components. For example, 7 assets (7! = 5040), 16 baches, of 100 paths will lead to 5040 * 16 * 100 = 8,064,000 numbers of MC simulation paths . The default is 100.
- mc_seednon negative int, optional
Random number generator seed. If it has a value other than None the random generator will be reseeded. The default value is None.
- finalonlyBoolean, optional
If it is False, the full schedule of weights is returned. Otherwise, only the prevailing weights are returned. The default is True.
- verboseBoolean, optional
If it is set to True, then various computation messages (meant as warnings) will be printed. The default is False.
- Returns:
- pandas.DataFrame
Portfolio weights for each fixing date. In the last row are the values corresponding to fixing_date.
Notes
If variance_reduction=True the total number of Monte Carlo simulations is mc_paths * nr_batches * M! where M is the number of portfolio components (symbols). For example, if mc_paths=10, mc_batches=16, and M=7 the total number of Monte Carlo simulations is 806,400. This feature should be used with care for portfolios with a relatively small number of component.
- set_mktdata(mktdata, colname=None, schedule=None, freq=None, sdate=None, edate=None, noffset=None, fixoffset=None, hlength=None)¶
Sets historical market data. It will overwrite the choice made in the constructor.
- Parameters:
- mktdatapandas.DataFrame
Historic daily market data for portfolio components in the format returned by azapy.mktData function.
- colnamestr, optional
Name of the price column from mktdata used in the weight’s calibration. The default is ‘adjusted’.
- scheduleazapy.schedule_simple, optional
External schedule of fixing dates. If it is None then the schedule of fixing dates will be generated internally. The default is None.
- fixing_datestr date-like, optional
Most recent fixing date used as reference for building the schedule of fixing dates. Must be a valid past business day present in the mktdata. It is relevant only if schedule is not Nona. The default is None.
- freqstr, optional
Rate of return horizon. It could be ‘Q’ for a quarter or ‘M’ for a month. The default is ‘M’.
- Returns:
- None
- set_rrate(rrate)¶
Sets portfolio components historical rates of return in the format “date”, “symbol1”, “symbol2”, etc.
- Parameters:
- rratepandas.DataFrame
The portfolio components historical rates of return. If it is not None, it will overwrite the rrate computed in the constructor from mktdata. The default is None.
- Returns:
- None
Example UniversalEngine¶
# Examples
import azapy as az
print(f"azapy version {az.version()}", flush=True)
#==============================================================================
# Collect market data
mktdir = '../../MkTdata'
sdate = '2012-01-01'
edate = 'today'
symb = ['GLD', 'TLT', 'XLV', 'IHI', 'VGT']
mktdata = az.readMkT(symb, sdate=sdate, edate=edate, file_dir=mktdir)
#==============================================================================
# build a fixing schedule
fixing_schedule = az.schedule_simple(sdate, edate,
freq='M', noffset=-5, fixoffset=0)
#==============================================================================
# compute weights
# using uniformly distributed random vectors in n-simplex
puniv = az.UniversalEngine(mktdata, schedule=fixing_schedule)
ww = puniv.getWeights(mc_paths=100, nr_batches=10, mc_seed=42, verbose=True)
print(f"weights\n{ww}")
# using Flat Dirichlet distribution (equivalent to above uniform distribution)
dirichlet_alpha = [1] * len(symb)
puniv = az.UniversalEngine(mktdata, schedule=fixing_schedule,
dirichlet_alpha=dirichlet_alpha)
ww = puniv.getWeights(mc_paths=100, nr_batches=10, mc_seed=42, verbose=True)
print(f"weights\n{ww}")
# using Dirichlet distribution with all alpha equal to 1/2
dirichlet_alpha = [0.5] * len(symb)
puniv = az.UniversalEngine(mktdata, schedule=fixing_schedule,
dirichlet_alpha=dirichlet_alpha)
ww = puniv.getWeights(mc_paths=100, nr_batches=10, mc_seed=42, verbose=True)
print(f"weights\n{ww}")
# using Dirichlet distribution with all alpha equal to the inverse number of
# portfolio symbols
dirichlet_alpha = [1 / len(symb)] * len(symb)
puniv = az.UniversalEngine(mktdata, schedule=fixing_schedule,
dirichlet_alpha=dirichlet_alpha)
ww = puniv.getWeights(mc_paths=100, nr_batches=10, mc_seed=42, verbose=True)
print(f"weights\n{ww}")
Port_Universal class¶
- class azapy.PortOpt.Port_Universal.Port_Universal(mktdata, symb=None, sdate=None, edate=None, col_price='close', col_divd='divd', col_ref='adjusted', pname='Port', pcolname=None, capital=100000, schedule=None, freq='Q', noffset=-3, fixoffset=-1, histoffset=3.25, calendar=None, multithreading=True, nsh_round=True)¶
Bases:
Port_Generator
Backtesting Cover’s (1996) Universal portfolio.
- Attributes
pname : str - portfolio name
ww : pandasDataFrame - portfolio weights at each rebalancing date
port : pandas.Series - portfolio historical time-series
schedule : pandas.DataFrame - rebalancing schedule
The most important method is set_model. It must be called before any other method.
Note: if ‘_CASH_’ asset is not explicitly present in the mktdata (as a portfolio cash component), then it will be added to the portfolio with a position (weight) net 0.
Methods
get_account
([fancy])Returns additional bookkeeping information regarding rebalancing (e.g., residual cash due rounding number of shares, previous period dividend cash accumulation, etc.)
Returns the actual market data used for portfolio evaluations.
Returns the number of shares held after each rolling date.
get_port
()Returns the portfolio time-series.
get_weights
([fancy])Returns the portfolio weights at each rebalancing period.
port_annual_returns
([withcomp, componly, fancy])Portfolio annual (calendar) rates of returns.
port_drawdown
([top, fancy, withcomp, componly])Computes the portfolio drawdowns.
port_monthly_returns
([withcomp, componly, fancy])Portfolio monthly (calendar) rate of returns.
port_perf
([componly, fancy])Brief description of portfolio and its components performances in terms of average historical rate of returns and maximum drawdowns.
port_period_perf
([fancy])Returns portfolio performance for each rolling period i.e. the rate of return, the rolling min and max returns, and max drawdown during the period.
port_period_returns
([fancy])Computes the rolling periods rate of returns.
port_quarterly_returns
([withcomp, componly, ...])Portfolio quarterly (calendar) rate of returns.
port_view
([emas, bollinger])Plots the portfolio time series together with optional technical indicators.
port_view_all
([sdate, edate, componly])Plots the portfolio and its component time-series on a relative basis.
set_model
([mc_paths, nr_batches, ...])Sets model parameters and evaluates portfolio time-series.
- __init__(mktdata, symb=None, sdate=None, edate=None, col_price='close', col_divd='divd', col_ref='adjusted', pname='Port', pcolname=None, capital=100000, schedule=None, freq='Q', noffset=-3, fixoffset=-1, histoffset=3.25, calendar=None, multithreading=True, nsh_round=True)¶
Constructor
- Parameters:
- mktdatapandas.DataFrame
MkT data in the format “symbol”, “date”, “open”, “high”, “low”, “close”, “volume”, “adjusted”, “divd”, “split” (e.g., as returned by azapy.readMkT function).
- symblist, optional
List of symbols for the basket components. All symbols MkT data should be included in mktdata. If set to None the symb will be set to include all the symbols from mktdata. The default is None.
- sdatedate like, optional
Start date for historical data. If set to None the sdate will be set to the earliest date in mktdata. The default is None.
- edatedate like, optional
End date for historical dates and so the simulation. Must be greater than sdate. If it is None then edate will be set to the latest date in mktdata. The default is None.
- col_pricestr, optional
Column name in the mktdata DataFrame that will be considered for portfolio aggregation. The default is ‘close’.
- col_divdstr, optional
Column name in the mktdata DataFrame that holds the dividend information. The default is ‘dvid’.
- col_refstr, optional
Column name in the mktdata DataFrame that will be used as a price reference for portfolio components. The default is ‘adjusted’.
- pnamestr, optional
The name of the portfolio. The default is ‘Port’.
- pcolnamestr, optional
Name of the portfolio price column. If it set to None then pcolname=pname. The default is None.
- capitalfloat, optional
Initial portfolio Capital in dollars. The default is 100000.
- schedulepandas.DataFrame, optional
Rebalancing schedule, with columns for ‘Droll’ rolling date and ‘Dfix’ fixing date. If it is None than the schedule will be set using the freq, noffset, fixoffset and calendar information. The default is None.
- freqstr, optional
Rebalancing frequency. It can be ‘Q’ for quarterly or ‘M’ for monthly rebalancing, respectively. It is relevant only if the schedule is None. The default is ‘Q’.
- noffsetint, optional
Number of business days offset for rebalancing date ‘Droll’ relative to the end of the period (quart or month). A positive value add business days beyond the calendar end of the period while a negative value subtracts business days. It is relevant only if the schedule is None. The default is -3.
- fixoffsetint, optional
Number of business day offset of fixing date ‘Dfix’ relative to the rebalancing date ‘Droll’. It can be 0 or negative. It is relevant only if the schedule is None. The default is -1.
- calendarnumpy.busdaycalendar, optional
Business calendar. If it is None then it will be set to NYSE business calendar. The default value is None.
- multithreadingBoolean, optional
If it is True then the rebalancing weights will be computed concurrent. The default is True.
- nsh_roundBoolean, optional
If it is True the invested numbers of shares are round to the nearest integer and the residual cash capital (positive or negative) is carried to the next reinvestment cycle. A value of False assumes investments with fractional number of shares (no rounding). The default is True.
- Returns:
- The object.
- get_account(fancy=False)¶
Returns additional bookkeeping information regarding rebalancing (e.g., residual cash due rounding number of shares, previous period dividend cash accumulation, etc.)
- Parameters:
- fancyBoolean, optional
False: the values are reported in unaltered algebraic format.
True : the values are reported rounded.
The default is False.
- Returns:
- `pandas.DataFrame`Reports, for each rolling period identified by ‘Droll’,
number of shares hold for each symbol,
‘cash_invst’ : cash invested at the beginning of period,
‘cash_roll’ : cash rolled to the next period,
‘cash_divd’ : cash dividend accumulated in the previous period.
Note: The capital at the beginning of the period is cash_invst + cash_roll. It is also equal to the previous period: value of the shares on the fixing date + cash_roll + cash_divd. There are 2 sources for the cash_roll. The roundup to integer number of shares and the shares close price differences between the fixing (computation) and rolling (execution) dates. It could be positive or negative. The finance of the cash_roll during each rolling period is assumed to be done separately by the investor.
- get_mktdata()¶
Returns the actual market data used for portfolio evaluations.
- Returns:
- `pandas.DataFrame`market data.
Returns the number of shares held after each rolling date.
- Returns:
- `pandas.DataFrame`number of shares per symbol.
- get_port()¶
Returns the portfolio time-series.
- Returns:
- `pandas.DataFrame`portfolio time-series.
- get_weights(fancy=False)¶
Returns the portfolio weights at each rebalancing period.
- Parameters:
- fancyBoolean, optional
False: reports the weights in algebraic format.
True: reports the weights in percentage rounded to 2 decimals.
The default is False.
- Returns:
- `pandas.DataFrame`portfolio weights per symbol.
- port_annual_returns(withcomp=False, componly=False, fancy=False)¶
Portfolio annual (calendar) rates of returns.
- Parameters:
- withcompBoolean, optional
If True, adds the portfolio components annual returns to the report. The default is False.
- componlyBoolean, optional
If True, only the portfolio components annual returns are reported. The flag is active only if withcomp=True. The default is False.
- fancyBoolean, optional
False : The rates are reported in unaltered algebraic format.
True :The rates are reported in percentage rounded to 2 decimals and presented is color style.
The default is False.
- Returns:
- `pandas.DataFrame`the report.
- port_drawdown(top=5, fancy=False, withcomp=False, componly=False)¶
Computes the portfolio drawdowns.
- Parameters:
- topint, optional
The number of largest drawdowns that will be reported. The default is 5.
- fancyBoolean, optional
- FalseThe drawdowns values are reported in unaltered
algebraic format.
- TrueThe drawdowns values are reported in percentage
rounded to 2 decimals.
The default is False.
- withcompBoolean, optional
If True, the portfolio components drawdowns are also reported. The default is False.
- componlyBoolean, optional
If True, only the portfolio components drawdowns are reported. The flag is active only if withcomp=True. The default is False.
- Returns:
- `panda.DataFrame`Table of drawdown events.
- Columns:
‘DD’ : drawdown rate
‘Date’ : recorded date of the drawdown
‘Star’ : start date of the drawdown
‘End’ : end date of the drawdown
- port_monthly_returns(withcomp=False, componly=False, fancy=False)¶
Portfolio monthly (calendar) rate of returns.
- Parameters:
- withcompBoolean, optional
If True, adds the portfolio components monthly returns to the report. The default is False.
- componlyBoolean, optional
If True, only the portfolio components monthly returns are reported. The flag is active only if withcomp=True. The default is False.
- fancyBoolean, optional
False : The rates are reported in unaltered algebraic format.
True : The rates are reported in percentage rounded to 2 decimals and presented is color style.
The default is False.
- Returns:
- `pandas.DataFrame`the report.
- port_perf(componly=False, fancy=False)¶
Brief description of portfolio and its components performances in terms of average historical rate of returns and maximum drawdowns.
- Parameters:
- componlyBoolean, optional
If True, only the portfolio components maximum drawdowns are reported. The default is False.
- fancyBoolean, optional
False : The rate of returns and drawdown values are reported in unaltered algebraic format.
True : The rate of returns and drawdown values are reported in percentage rounded to 2 decimals.
The default is False.
- Returns:
- `pandas.DataFrame`Performance information.
- Columns
‘RR’ : rate of returns
‘DD’ : maximum rate of drawdown
‘RoMaD’ : abs(RR/DD), Rate of Return over Maximum Drawdown
‘DD_date’ : recorder date of maximum drawdown
‘DD_start’ : start date of maximum drawdown
‘DD_end’ : end date of maximum drawdown
- port_period_perf(fancy=False)¶
Returns portfolio performance for each rolling period i.e. the rate of return, the rolling min and max returns, and max drawdown during the period.
- Parameters:
- fancyBoolean, optional
False: returns in algebraic form.
True: returns percentage rounded to 2 decimals.
- The default is `False`.
- Returns:
- pandas.DataFrame
‘Droll’ - indicates the start of the period.
‘RR’ - period rate of return.
‘RR_Min’ - minimum rolling rate of return in the period.
‘RR_Max’ - maximum rolling rate of return in the period.
‘DD_Max’ - maximum drawdown in the period.
‘RR_Min_Date’ - date of ‘RR_Min’.
‘RR_Max_Date’ - date of ‘RR_Max’.
‘DD_Max_Date’ - date of ‘DD_Max’.
- port_period_returns(fancy=False)¶
Computes the rolling periods rate of returns.
- Parameters:
- fancyBoolean, optional
False: returns in algebraic form.
True: returns percentage rounded to 2 decimals.
- The default is `False`.
- Returns:
- `pandas.DataFrame`The report.
Each rolling period is indicated by its start date, ‘Droll’. Included are the fixing data, ‘Dfix’, and the portfolio weights.
- port_quarterly_returns(withcomp=False, componly=False, fancy=False)¶
Portfolio quarterly (calendar) rate of returns.
- Parameters:
- withcompBoolean, optional
If True, adds the portfolio components monthly returns to the report. The default is False.
- componlyBoolean, optional
If True, only the portfolio components monthly returns are reported. The flag is active only if withcomp=True. The default is False.
- fancyBoolean, optional
False : The rates are reported in unaltered algebraic format.
True : The rates are reported in percentage rounded to 2 decimals and presented is color style.
The default is False.
- Returns:
- `pandas.DataFrame`the report.
- port_view(emas=[30, 200], bollinger=False, **opt)¶
Plots the portfolio time series together with optional technical indicators.
- Parameters:
- emaslist of int, optional
List of EMA durations. The default is [30, 200].
- bollingerBoolean, optional
If set True it adds the Bollinger bands. The default is False.
- **optother optional parameters
- fancyBoolean, optional
False : it uses the matplotlib capabilities.
True : it uses plotly library for interactive time-series view.
The default is False.
title : str, optional plot title. The default is ‘Port performance’.
xlabel : str, optional name of x-axis. The default is ‘date’.
ylabel : str; optional name of y-axis. The default is None.
- savetostr, optional
The name of the file where to save the plot. The default is None.
- Returns:
- `pandas.DataFrame`Contains the time-series included in plot.
- port_view_all(sdate=None, edate=None, componly=False, **opt)¶
Plots the portfolio and its component time-series on a relative basis.
- Parameters:
- sdatedate like, optional
Start date of plotted time-series. If it is set to None then the sdate is set to the earliest date in the time-series. The default is None.
- edatedate like, optional
End date of plotted time-series. If it set to None, then the edate is set to the most recent date of the time-series. The default is None.
- componlyBoolean, optional
True : only the portfolio components time-series are plotted.
False: the portfolio and its components times-series are plotted.
The default is True.
- **optother parameters
- fancyBoolean, optional
False : it uses the pandas plot (matplotlib) capabilities.
True : it uses plotly library for interactive time-series view.
The default is False.
title : str, optional plot title. The default is ‘Relative performance’.
xlabel : str, optional name of x-axis. The default is ‘date’.
ylabel : str; optional name of y-axis. The default is None.
- savetostr, optional
The name of the file where to save the plot. The default is None.
- Returns:
- `pandas.DataFrame`A Data Frame containing the time-series.
- set_model(mc_paths=100, nr_batches=16, variance_reduction=True, dirichlet_alpha=None, mc_seed=None, verbose=False, **kwarg)¶
Sets model parameters and evaluates portfolio time-series.
- Parameters:
- mc_pathspositive int, optional
Number of Monte Carlo simulations The default is 100.
- nr_batchespositive int, optional
Number of Monte Carlo simulation batches. Each batch runs mc_paths simulations. The computation is multithreaded for nr_batches > 1. The default is 16.
- variance_reductionBoolean, optional
If set to True, then the antithetic variance reduction based on all possible permutations of the basket components is deployed. In this case the total number of MC simulations is mc_paths * nr_batches * factorial(number of portfolio components). For example, a portfolio of 6 assets, with default values for mc_paths and nr_batches implies 100 * 16 * 720 = 1,1520,000 MC simulations. If it is set to False, then the total number of simulations is mc_paths * nr_batches. The default is True.
- mc_seedpositive int, optional
Random number generator seed. If it set to a positive int the Monte Carlo random number generator is reseeded. The default is None.
- dirichlet_alphalist, optional
The alpha values for Dirichlet random vector generator. Must have the size equal to the number of portfolio components. If it is set to None then the uniform random generator vectors in a n-simplex is used (equivalent to Flat Dirichlet random vector generator, i.e., alpha=[1] * n). The default is None.
- verboseBoolean, optional
Logical flag triggering the verbose mode. The default is False.
- Returns:
- `pandas.DataFrame`The portfolio time-series in the format ‘date’,
- ‘pcolname’.
Example Port_Universal¶
# Examples
import pandas as pd
import azapy as az
print(f"azapy version {az.version()}", flush=True)
#==============================================================================
# Collect market data
mktdir = '../../MkTdata'
sdate = '2012-01-01'
edate = 'today'
symb = ['GLD', 'TLT', 'XLV', 'IHI', 'VGT', 'OIH']
mktdata = az.readMkT(symb, sdate=sdate, edate=edate, file_dir=mktdir)
#=============================================================================
# Compute Cover's (1996) Universal portfolio
p4 = az.Port_Universal(mktdata, pname='UnivPort')
port4 = p4.set_model(mc_paths=100, nr_batches=20, verbose=True)
ww = p4.get_weights()
_ = p4.port_view()
_ = p4.port_view_all()
performance = p4.port_perf()
drawdowns = p4.port_drawdown()
aret = p4.port_annual_returns()
qret = p4.port_quarterly_returns()
mret = p4.port_monthly_returns()
pret = p4.port_period_returns()
nsh = p4.get_nshares()
acc = p4.get_account(fancy=True)
with pd.option_context('display.max_columns', None):
print(f"Weights\n{ww.round(4)}")
print(f"Performance\n{performance.round(4)}")
print(f"Portfolio Historical Drawdowns\n{drawdowns.round(4)}")
print(f"Portfolio Annual Returns\n{aret.round(4)}")
print(f"Portfolio Quarterly Returns\n{qret.round(4)}")
print(f"Portfolio Monthly Returns\n{mret.round(4)}")
print(f"Portfolio Period Returns\n{pret.round(2)}")
print(f"Numbers of Shares Invested\n{nsh}")
print(f"Account Info\n{acc}")
# Test using the Port_Rebalanced weights = ww (from above)
p2 = az.Port_Rebalanced(mktdata, pname='TestPort')
port2 = p2.set_model(ww)
# Compare - must be identical
port4.merge(port2, how='left', on='date').plot()