Portfolio Management

As mentioned above, FinQuant is a program for financial portfolio management, among others. The module finquant.portfolio does exactly that.

Note

The impatient reader who simply wants to jump in and start using FinQuant is advised to jump to build_portfolio and have a look at and play around with the Examples.

This module is the core of FinQuant. It provides

  • a public class Stock that holds and calculates quantities of a single stock,
  • a public class Portfolio that holds and calculates quantities of a financial portfolio, which is a collection of Stock instances.
  • a public function build_portfolio() that automatically constructs and returns an instance of Portfolio and instances of Stock. The relevant stock data is either retrieved through quandl/yfinance or provided by the user as a pandas.DataFrame (after loading it manually from disk/reading from file). For an example on how to use it, please read the corresponding docstring, or have a look at the examples in the sub-directory example.

The classes Stock and Portfolio are designed to easily manage your financial portfolio, and make the most common quantitative calculations, such as:

  • cumulative returns of the portfolio’s stocks
  • daily returns of the portfolio’s stocks (daily percentage change),
  • daily log returns of the portfolio’s stocks,
  • Expected (annualised) Return,
  • Volatility,
  • Sharpe Ratio,
  • skewness of the portfolio’s stocks,
  • Kurtosis of the portfolio’s stocks,
  • the portfolio’s covariance matrix.

Furthermore, the constructed portfolio can be optimised for

  • minimum Volatility,
  • maximum Sharpe Ratio
  • minimum Volatility for a given Expected Return
  • maximum Sharpe Ratio for a given target Volatility

by either performing a numerical computation to solve a minimisation problem, or by performing a Monte Carlo simulation of n trials. The former should be the preferred method for reasons of computational effort and accuracy. The latter is only included for the sake of completeness.

Finally, functions are implemented to generated the following plots:

  • Monte Carlo run to find optimal portfolio(s)
  • Efficient Frontier
  • Portfolio with the minimum Volatility based a numerical optimisation
  • Portfolio with the maximum Sharpe Ratio based on a numerical optimisation
  • Portfolio with the minimum Volatility for a given Expected Return based on a numerical optimisation
  • Portfolio with the maximum Sharpe Ratio for a given target Volatility based on a numerical optimisation
  • Individual stocks of the portfolio (Expected Return over Volatility)

Stock

class finquant.portfolio.Stock(investmentinfo, data)

Object that contains information about a stock/fund. To initialise the object, it requires a name, information about the stock/fund given as one of the following data structures:

  • pandas.Series
  • pandas.DataFrame

The investment information can contain as little information as its name, and the amount invested in it, the column labels must be Name and Allocation respectively, but it can also contain more information, such as

  • Year
  • Strategy
  • CCY
  • etc.

It also requires either data, e.g. daily closing prices as a pandas.DataFrame or pandas.Series. data must be given as a pandas.DataFrame, and at least one data column is required to containing the closing price, hence it is required to contain one column label <stock_name> - Adj. Close which is used to compute the return of investment. However, data can contain more data in additional columns.

__init__(investmentinfo, data)
Input:
investmentinfo:pandas.DataFrame of investment information
data:pandas.DataFrame of stock price
comp_daily_returns()

Computes the daily returns (percentage change). See finquant.returns.daily_returns.

comp_expected_return(freq=252)

Computes the Expected Return of the stock.

Input:
freq:int (default: 252), number of trading days, default value corresponds to trading days in a year
Output:
expected_return:
 Expected Return of stock.
comp_volatility(freq=252)

Computes the Volatility of the stock.

Input:
freq:int (default: 252), number of trading days, default value corresponds to trading days in a year
Output:
volatility:Volatility of stock.
properties()

Nicely prints out the properties of the stock: Expected Return, Volatility, Skewness, Kurtosis as well as the Allocation (and other information provided in investmentinfo.)

Portfolio

class finquant.portfolio.Portfolio

Object that contains information about a investment portfolio. To initialise the object, it does not require any input. To fill the portfolio with investment information, the function add_stock(stock) should be used, in which stock is an object of Stock.

__init__()

Initiates Portfolio.

add_stock(stock)

Adds a stock of type Stock to the portfolio. Each time add_stock is called, the following instance variables are updated:

  • portfolio: pandas.DataFrame, adds a column with information from stock
  • stocks: dictionary, adds an entry for stock
  • data: pandas.DataFrame, adds a column of stock prices from stock

Also, the following instance variables are (re-)computed:

  • expected_return: Expected Return of the portfolio
  • volatility: Volatility of the portfolio
  • sharpe: Sharpe Ratio of the portfolio
  • skew: Skewness of the portfolio’s stocks
  • kurtosis: Kurtosis of the portfolio’s stocks
Input:
stock:an object of Stock
comp_cov()

Compute and return a pandas.DataFrame of the covariance matrix of the portfolio.

Output:
cov:a pandas.DataFrame of the covariance matrix of the portfolio.
comp_cumulative_returns()

Computes the cumulative returns of all stocks in the portfolio. See finquant.returns.cumulative_returns.

Output:
ret:a pandas.DataFrame of cumulative returns of given stock prices.
comp_daily_log_returns()

Computes the daily log returns of all stocks in the portfolio. See finquant.returns.daily_log_returns.

Output:
ret:a pandas.DataFrame of log Returns
comp_daily_returns()

Computes the daily returns (percentage change) of all stocks in the portfolio. See finquant.returns.daily_returns.

Output:
ret:a pandas.DataFrame of daily percentage change of Returns of given stock prices.
comp_expected_return(freq=252)

Computes the Expected Return of the portfolio.

Input:
freq:int (default: 252), number of trading days, default value corresponds to trading days in a year.
Output:
expected_return:
 float the Expected Return of the portfolio.
comp_mean_returns(freq=252)

Computes the mean returns based on historical stock price data. See finquant.returns.historical_mean_return.

Input:
freq:int (default: 252), number of trading days, default value corresponds to trading days in a year.
Output:
ret:a pandas.DataFrame of historical mean Returns.
comp_sharpe()

Compute and return the Sharpe Ratio of the portfolio.

Output:
sharpe:float, the Sharpe Ratio of the portfolio
comp_stock_volatility(freq=252)

Computes the Volatilities of all the stocks individually

Input:
freq:int (default: 252), number of trading days, default value corresponds to trading days in a year.
Output:
volatilies:pandas.DataFrame with the individual Volatilities of all stocks of the portfolio.
comp_volatility(freq=252)

Computes the Volatility of the given portfolio.

Input:
freq:int (default: 252), number of trading days, default value corresponds to trading days in a year.
Output:
volatility:float the Volatility of the portfolio.
comp_weights()

Computes and returns a pandas.Series of the weights/allocation of the stocks of the portfolio.

Output:
weights:a pandas.Series with weights/allocation of all stocks within the portfolio.
ef_efficient_frontier(targets=None)

Interface to finquant.efficient_frontier.EfficientFrontier.efficient_frontier.

Gets portfolios for a range of given target Returns. If no targets were provided, the algorithm will find the minimum and maximum Returns of the portfolio’s individual stocks, and set the target range according to those values. Results in the Efficient Frontier.

Input:
targets:list/numpy.ndarray (default: None) of floats, range of target Returns.
Output:
efrontier:numpy.ndarray of (Volatility, Return) values.
ef_efficient_return(target, verbose=False)

Interface to finquant.efficient_frontier.EfficientFrontier.efficient_return.

Finds the portfolio with the minimum Volatility for a given target return.

Input:
target:float, the target return of the optimised portfolio.
verbose:boolean (default= False), whether to print out properties or not.
Output:
df_weights:a pandas.DataFrame of weights/allocation of stocks within the optimised portfolio.
ef_efficient_volatility(target, verbose=False)

Interface to finquant.efficient_frontier.EfficientFrontier.efficient_volatility.

Finds the portfolio with the maximum Sharpe Ratio for a given target Volatility.

Input:
target:float, the target Volatility of the optimised portfolio.
verbose:boolean (default= False), whether to print out properties or not.
Output:
df_weights:a pandas.DataFrame of weights/allocation of stocks within the optimised portfolio.
ef_maximum_sharpe_ratio(verbose=False)

Interface to finquant.efficient_frontier.EfficientFrontier.maximum_sharpe_ratio.

Finds the portfolio with the maximum Sharpe Ratio, also called the tangency portfolio.

Input:
verbose:boolean (default= False), whether to print out properties or not.
Output:
df_weights:a pandas.DataFrame of weights/allocation of stocks within the optimised portfolio.
ef_minimum_volatility(verbose=False)

Interface to finquant.efficient_frontier.EfficientFrontier.minimum_volatility.

Finds the portfolio with the minimum Volatility.

Input:
verbose:boolean (default= False), whether to print out properties or not.
Output:
df_weights:a pandas.DataFrame of weights/allocation of stocks within the optimised portfolio.
ef_plot_efrontier()

Interface to finquant.efficient_frontier.EfficientFrontier.plot_efrontier.

Plots the Efficient Frontier.

ef_plot_optimal_portfolios()

Interface to finquant.efficient_frontier.EfficientFrontier.plot_optimal_portfolios.

Plots markers of the optimised portfolios for

  • minimum Volatility, and
  • maximum Sharpe Ratio.
get_stock(name)

Returns the instance of Stock with name name.

Input:
name:string of the name of the stock that is returned. Must match one of the labels in the dictionary self.stocks.
Output:
stock:instance of Stock.
mc_optimisation(num_trials=1000)

Interface to finquant.monte_carlo.MonteCarloOpt.optimisation.

Optimisation of the portfolio by performing a Monte Carlo simulation.

Input:
num_trials:int (default: 1000), number of portfolios to be computed, each with a random distribution of weights/allocation in each stock.
Output:
opt_w:pandas.DataFrame with optimised investment strategies for maximum Sharpe Ratio and minimum Volatility.
opt_res:pandas.DataFrame with Expected Return, Volatility and Sharpe Ratio for portfolios with minimum Volatility and maximum Sharpe Ratio.
mc_plot_results()

Plots the results of the Monte Carlo run, with all of the randomly generated weights/portfolios, as well as markers for the portfolios with the

  • minimum Volatility, and
  • maximum Sharpe Ratio.
mc_properties()

Calculates and prints out Expected annualised Return, Volatility and Sharpe Ratio of optimised portfolio.

plot_stocks(freq=252)

Plots the Expected annual Returns over annual Volatility of the stocks of the portfolio.

Input:
freq:int (default: 252), number of trading days, default value corresponds to trading days in a year.
properties()

Nicely prints out the properties of the portfolio:

  • Expected Return,
  • Volatility,
  • Sharpe Ratio,
  • skewness,
  • Kurtosis

as well as the allocation of the stocks across the portfolio.

build_portfolio

portfolio.build_portfolio()

This function builds and returns an instance of Portfolio given a set of input arguments.

Input:
pf_allocation:

(optional) pandas.DataFrame with the required data column labels Name and Allocation of the stocks. If not given, it is automatically generated with an equal weights for all stocks in the resulting portfolio.

names:

(optional) A string or list of strings, containing the names of the stocks, e.g. “GOOG” for Google.

start_date:

(optional) string/datetime start date of stock data to be requested through quandl/yfinance (default: None).

end_date:

(optional) string/datetime end date of stock data to be requested through quandl/yfinance (default: None).

data:

(optional) A pandas.DataFrame which contains quantities of the stocks listed in pf_allocation.

data_api:

(optional) A string (default: quandl) which determines how to obtain stock prices, if data is not provided by the user. Valid values:

  • quandl (Python package/API to Quandl)
  • yfinance (Python package formerly known as fix-yahoo-finance)
Output:
pf:Instance of Portfolio which contains all the information requested by the user.

Note

Only the following combinations of inputs are allowed:

  • names, pf_allocation (optional), start_date (optional), end_date (optional), data_api (optional)
  • data, pf_allocation (optional)

The two different ways this function can be used are useful for:

  1. building a portfolio by pulling data from quandl/yfinance,
  2. building a portfolio by providing stock data which was obtained otherwise, e.g. from data files.

If used in an unsupported way, the function (or subsequently called function) raises appropriate Exceptions with useful information what went wrong.