Buy and Hold portfolio

A Buy and Hold strategy assumes that at some point in time the entire capital is invested in a portfolio with fixed composition, i.e., fixed numbers of shares. After that, the portfolio is held until its liquidation. No rebalancing is involved.

The backtesting of this strategy could be viewed as a performance benchmark.

There is 1 support class:

  • Port_Simple : performs portfolio backtesting, out-of-sample analysis.

The Port_Simple class can be used also as a tool to compare the performance of multiple portfolios if their time-series are known.

TOP

Port_Simple class

class azapy.Generators.Port_Simple.Port_Simple(mktdata, symb=None, sdate=None, edate=None, col='adjusted', pname='Port', pcolname=None, capital=100000)

Bases: object

Backtesting the Buy and Hold portfolio.

Attributes
  • pname : str - portfolio name

  • ww : pandasDataFrame - portfolio weights at each rebalancing date

  • port : pandas.Series - portfolio historical time-series

The most important method is set_model. It must be called before any other method.

Methods

get_mktdata()

Returns the actual market data used for portfolio evaluations.

get_nshares()

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_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([ww, verbose])

Set model parameters and evaluate the portfolio time-series.

__init__(mktdata, symb=None, sdate=None, edate=None, col='adjusted', pname='Port', pcolname=None, capital=100000)

Constructor

Parameters:
mktdatapandas.DataFrame, dict of pandas.DataFrame, list of

pandas.Series or single column pandas.DataFrame of prices; MkT data in the format “symbol”, “date”, “open”, “high”, “low”, “close”, “volume”, “adjusted”, “divd”, “split” (e.g., as returned by azapy.readMkT function either as a dict or as a single DataFrame).

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 the full set of symbols included in 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.

colstr, optional

Name of column in the mktdata DataFrame that will be considered for portfolio aggregation. 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 that pcolname=pname. The default is None.

capitalfloat, optional

Initial portfolio Capital in dollars. The default is 100000.

Returns:
The object.
get_mktdata()

Returns the actual market data used for portfolio evaluations.

Returns:
`pandas.DataFrame`market data.
get_nshares()

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_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(ww=None, verbose=False)

Set model parameters and evaluate the portfolio time-series.

Parameters:
wwlist (also numpy.array or pandas.Series), optional

List of weights. If it is pandas.Series the index should match the basket symb. Otherwise, the weights are considered in the symb order. If it is set to None than ww will be set to equal weights. The default is None.

verbose: `Boolean`, optional

If it True, then various computational messages will be printed. The default is False.

Returns:
`pandas.DataFrame`The portfolio time-series in the format “date”,
“pcolname”.

TOP

Example Buy and Hold use of Port_Simple

# Examples
import azapy as az

#=============================================================================
# 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)

#=============================================================================
# define some weights 
ww = list(range(1,len(symb) + 1))

print(f"weights:\n{ww}\n")
#=============================================================================
# Compute portfolio and view the results
p1 = az.Port_Simple(mktdata, pname='SimplePort')
port = p1.set_model(ww)

_ = p1.port_view()
_ = p1.port_view_all()
drawdown = p1.port_drawdown(fancy=True)
perf = p1.port_perf(fancy=True)
annual = p1.port_annual_returns()
quarterly = p1.port_quarterly_returns()
monthly = p1.port_monthly_returns()

print(f"Portfolio Drawdown\n{drawdown}")
print(f"Portfolio performance\n{perf}")
print(f"Annual Returns\n{annual}")
print(f"Quarterly Returns\n{quarterly}")
print(f"Monthly Returns\n{monthly}")

TOP

Example Port_Simple used as a portfolio comparison tool

# Examples - use Port_Simple as a tool to compare price time-series
import azapy as az

#=============================================================================
# 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)

# transform mktdata into a list of DataFrame's containing close prices
lmktdata = []
for k, v in mktdata.groupby(by='symbol'):
    lmktdata.append(v.pivot(columns='symbol', values='close').iloc[:,0])

# use lmktdata as a collection of price time-series
# in a real life example lmktdata could be a list of portfolios time-series

#=============================================================================
# set Port_Simple class
p1 = az.Port_Simple(lmktdata, pname='SimplePort')
# must call set_model
port = p1.set_model()

# print info about the initial time-sereis
_ = p1.port_view_all(componly=True)
perf = p1.port_perf(componly=True, fancy=True)
annual = p1.port_annual_returns(withcomp=True, componly=True)
quarterly = p1.port_quarterly_returns(withcomp=True, componly=True)
monthly = p1.port_monthly_returns(withcomp=True, componly=True)
print(f"Portfolios Performance\n{perf}")
print(f"Annual Retuns\n{annual.round(4)}")
print(f"Quarterly Retuns\n{quarterly.round(4)}")
print(f"Monthly Retuns\n{monthly.round(4)}")

TOP