# Examples¶

Note

In the below examples, pf refers to an instance of finquant.portfolio.Portfolio, the object that holds all stock prices and computes its most common quantities automatically. To make FinQuant a user-friendly program, that combines data analysis, visualisation and optimisation, the object also provides interfaces to the main features that are provided in the modules in ./finquant/ and are discussed throughout this documentation.

## Building a portfolio with data from web quandl/yfinance¶

This example shows how to use FinQuant to build a financial portfolio by downloading stock price data by using the Python package quandl/yfinance.

Note

This example refers to example/Example-Build-Portfolio-from-web.py of the GitHub repository. It can be downloaded with jupyter notebook cell information: download Example-Build-Portfolio-from-web.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 # # Building a portfolio with data from quandl/yfinance # ## Building a portfolio with build_portfolio() by downloading relevant data through quandl/yfinance with stock names, start and end date and column labels # This example only focuses on how to use build_portfolio() to get an instance of Portfolio by providing minimal information that is passed on to quandl/yfinance. For a more exhaustive description of this package and example, please try Example-Analysis and Example-Optimisation. import pandas as pd import datetime # importing some custom functions/objects from finquant.portfolio import build_portfolio # ## Get data from quandl/yfinance and build portfolio # First we need to build a pandas.DataFrame that holds relevant data for our portfolio. The minimal information needed are stock names and the amount of money to be invested in them, e.g. Allocation. # To play around yourself with different stocks, here is a short list of companies and their tickers # d = {0: {'Name':'WIKI/GOOG', 'Allocation':20}, # Google # 1: {'Name':'WIKI/AMZN', 'Allocation':33}, # Amazon # 2: {'Name':'WIKI/MSFT', 'Allocation':18}, # Microsoft # 3: {'Name':'WIKI/AAPL', 'Allocation':10}, # Apple # 4: {'Name':'WIKI/KO', 'Allocation':15}, # Coca-Cola # 5: {'Name':'WIKI/XOM', 'Allocation':11}, # Exxon Mobil # 6: {'Name':'WIKI/JPM', 'Allocation':21}, # JP Morgan # 7: {'Name':'WIKI/DIS', 'Allocation':9}, # Disney # 8: {'Name':'WIKI/MCD', 'Allocation':23}, # McDonald's # 9: {'Name':'WIKI/WMT', 'Allocation':3}, # Walmart # 10: {'Name':'WIKI/YHOO', 'Allocation':7}, # Yahoo # 11: {'Name':'WIKI/GS', 'Allocation':9}, # Goldman Sachs # } d = { 0: {"Name": "WIKI/GOOG", "Allocation": 20}, 1: {"Name": "WIKI/AMZN", "Allocation": 10}, 2: {"Name": "WIKI/MCD", "Allocation": 15}, 3: {"Name": "WIKI/DIS", "Allocation": 18}, } # If you wish to use Yahoo Finance as source, you must remove "WIKI/" from the stock names/tickers pf_allocation = pd.DataFrame.from_dict(d, orient="index") # ### User friendly interface to quandl/yfinance # As mentioned above, in this example build_portfolio() is used to build a portfolio by performing a query to quandl/yfinance. # # To download Google's stock data, quandl requires the string "WIKI/GOOG". For simplicity, FinQuant facilitates a set of functions under the hood to sort out lots of specific commands/required input for quandl/yfinance. When using FinQuant, the user simply needs to provide a list of stock names/tickers. # For example, if using quandl as a data source (default), a list of names/tickers as shown below is a valid input for FinQuant's function build_portfolio(names=names): # * names = ["WIKI/GOOG", "WIKI/AMZN"] # # If using yfinance as a data source, FinQuant's function build_portfolio(names=names) expects the stock names to be without any leading/trailing string (check Yahoo Finance for correct stock names): # * names = ["GOOG", "AMZN"] # # By default, FinQuant uses quandl to obtain stock price data. The function build_portfolio() can be called with the optional argument data_api to use yfinance instead: # * build_portfolio(names=names, data_api="yfinance") # # In the below example we are using the default option, quandl. # here we set the list of names based on the names in # the DataFrame pf_allocation names = pf_allocation["Name"].values.tolist() # dates can be set as datetime or string, as shown below: start_date = datetime.datetime(2015, 1, 1) end_date = "2017-12-31" # While quandl/yfinance will download lots of different prices for each stock, # e.g. high, low, close, etc, FinQuant will extract the column "Adj. Close" ("Adj Close" if using yfinance). pf = build_portfolio( names=names, pf_allocation=pf_allocation, start_date=start_date, end_date=end_date ) # ## Portfolio is successfully built # Getting data from the portfolio # the portfolio information DataFrame print(pf.portfolio) # the portfolio stock data, prices DataFrame print(pf.data.head(3)) # print out information and quantities of given portfolio print(pf) pf.properties() # ## Please continue with Example-Build-Portfolio-from-file.py. # As mentioned above, this example only shows how to use build_portfolio() to get an instance of Portfolio by downloading data through quandl/yfinance. 

## Building a portfolio with preset data¶

This example shows how to use FinQuant to build a financial portfolio by providing stock price data yourself, e.g. by reading data from disk/file.

Note

This example refers to example/Example-Build-Portfolio-from-file.py of the GitHub repository. It can be downloaded with jupyter notebook cell information: download Example-Build-Portfolio-from-file.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 # # Building a portfolio with data from disk # ## Building a portfolio with build_portfolio() with data obtained from data files. # Note: The stock data is provided in two data files. The stock data was previously pulled from quandl. import pathlib import pandas as pd import datetime # importing FinQuant's function to automatically build the portfolio from finquant.portfolio import build_portfolio # ### Get data from disk/file # Here we use pandas.read_cvs() method to read in the data. # stock data was previously pulled from quandl and stored in ex1-stockdata.csv # commands used to save data: # pf.portfolio.to_csv("ex1-portfolio.csv", encoding='utf-8', index=False, header=True) # pf.data.to_csv("ex1-stockdata.csv", encoding='utf-8', index=True, index_label="Date") # read data from files: df_pf_path = pathlib.Path.cwd() / ".." / "data" / "ex1-portfolio.csv" df_data_path = pathlib.Path.cwd() / ".." / "data" / "ex1-stockdata.csv" df_pf = pd.read_csv(df_pf_path) df_data = pd.read_csv(df_data_path, index_col="Date", parse_dates=True) # ### Examining the DataFrames print(df_pf) print(df_data.head(3)) # ## Building a portfolio with build_portfolio() # build_portfolio() is an interface that can be used in different ways. Two of which is shown below. For more information the docstring is shown below as well. # In this example build_portfolio() is being passed df_data, which was read in from file above. print(build_portfolio.__doc__) # ## Building a portfolio with data only # Below is an example of only passing a DataFrame containing data (e.g. stock prices) to build_portfolio() in order to build an instance of Portfolio. In this case, the allocation of stocks is automatically generated by equally distributing the weights across all stocks. # building a portfolio by providing stock data pf = build_portfolio(data=df_data) # ### Portfolio is successfully built # Below it is shown how the allocation of the stocks and the data (e.g. prices) of the stocks can be obtained from the object pf. # the portfolio information DataFrame print(pf.portfolio.name) print(pf.portfolio) # the portfolio stock data, prices DataFrame print(pf.data.head(3)) # ## Building a portfolio with data and desired allocation # If a specific allocation of stocks in the portfolio is desired, a DataFrame such as df_pf (which was read from file above) can be passed to build_portfolio() as shown below. # building a portfolio by providing stock data # and a desired allocation pf2 = build_portfolio(data=df_data, pf_allocation=df_pf) # the portfolio information DataFrame print(pf2.portfolio.name) print(pf2.portfolio) # the portfolio stock data, prices DataFrame print(pf2.data.head(3)) 

## Analysis of a portfolio¶

This example shows how to use an instance of finquant.portfolio.Portfolio, get the portfolio’s quantities, such as

• Expected Returns,
• Volatility,
• Sharpe Ratio.

It also shows how to extract individual stocks from the given portfolio. Moreover it shows how to compute and visualise:

• the different Returns provided by the module finquant.returns,
• Moving Averages, a band of Moving Averages, and a Bollinger Band.

Note

This example refers to example/Example-Analysis.py of the GitHub repository. It can be downloaded with jupyter notebook cell information: download Example-Analysis.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 # # Example: # ## Building a portfolio with build_portfolio() with data obtained from data files. # Note: The stock data is provided in two data files. The stock data was previously pulled from quandl. import pathlib import matplotlib.pyplot as plt import pandas as pd import datetime # importing FinQuant's function to automatically build the portfolio from finquant.portfolio import build_portfolio # ## Building a portfolio with build_portfolio() # As in previous example, using build_portfolio() to generate an object of Portfolio. # read data from files: df_data_path = pathlib.Path.cwd() / ".." / "data" / "ex1-stockdata.csv" df_data = pd.read_csv(df_data_path, index_col="Date", parse_dates=True) # building a portfolio by providing stock data pf = build_portfolio(data=df_data) # ## Expected Return, Volatility and Sharpe Ratio of Portfolio # The annualised expected return and volatility as well as the Sharpe Ratio are automatically computed. They are obtained as shown below. # The expected return and volatility are based on 252 trading days by default. The Sharpe Ratio is computed with a risk free rate of 0.005 by default. # expected (annualised) return print(pf.expected_return) # volatility print(pf.volatility) # Sharpe ratio (computed with a risk free rate of 0.005 by default) print(pf.sharpe) # ## Getting Skewness and Kurtosis of the stocks print(pf.skew) print(pf.kurtosis) # ## Nicely printing out portfolio quantities # To print the expected annualised return, volatility, Sharpe ratio, skewness and Kurtosis of the portfolio and its stocks, one can simply do pf.properties(). print(pf) pf.properties() # ## Daily returns and log returns # FinQuant provides functions to compute daily returns and annualised mean returns of a given DataFrame in various ways. # annualised mean returns print(pf.comp_mean_returns()) # daily returns (percentage change) print(pf.comp_cumulative_returns().head(3)) print(pf.comp_daily_log_returns().head(3)) # plotting stock data of portfolio pf.data.plot() plt.show() # The stock prices of Google and Amazon are much higher than those for McDonald's and Disney. Hence the fluctuations of the latter ones are barely seen in the above plot. One can use pandas.plot() method to create a secondary y axis. pf.data.plot(secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True) plt.show() # plotting cumulative returns (price_{t} - price_{t=0}) / price_{t=0} pf.comp_cumulative_returns().plot().axhline(y=0, color="black", lw=3) plt.show() # plotting daily percentage changes of returns pf.comp_daily_returns().plot().axhline(y=0, color="black") plt.show() # plotting daily log returns pf.comp_daily_log_returns().plot().axhline(y=0, color="black") plt.show() # cumulative log returns pf.comp_daily_log_returns().cumsum().plot().axhline(y=0, color="black") plt.show() # ## Moving Averages # FinQuant provides a module finquant.moving_average to compute moving averages. See below. from finquant.moving_average import sma # simple moving average ax = pf.data.plot(secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True) # computing simple moving average over a span of 50 (trading) days # and plotting it sma(pf.data, span=50).plot(ax=ax, secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True) plt.show() from finquant.moving_average import ema # exponential moving average ax = pf.data.plot(secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True) # computing exponential moving average and plotting it ema(pf.data).plot(ax=ax, secondary_y=["WIKI/MCD", "WIKI/DIS"]) plt.show() # ## Band of moving averages and Buy/Sell signals # FinQuant also provides a method finquant.moving_average.compute_ma that automatically computes and plots several moving averages. It also **finds buy/sell signals based on crossovers** of the shortest and longest moving average. # To learn more about it and its input arguments, read its docstring and see the example below. from finquant.moving_average import compute_ma print(compute_ma.__doc__) # get stock data for disney dis = pf.get_stock("WIKI/DIS").data.copy(deep=True) # we want moving averages of 10, 50, 100, and 200 days. spans = [10, 50, 100, 150, 200] # compute and plot moving averages dis_ma = compute_ma(dis, ema, spans, plot=True) plt.show() # ## Plot the Bollinger Band of one stock # The Bollinger Band can be automatically computed and plotted with the method finquant.moving_average.plot_bollinger_band. See below for an example. # plot the bollinger band of the disney stock prices from finquant.moving_average import plot_bollinger_band # get stock data for disney dis = pf.get_stock("WIKI/DIS").data.copy(deep=True) span = 20 # for simple moving average: plot_bollinger_band(dis, sma, span) plt.show() # for exponential moving average: plot_bollinger_band(dis, ema, span) plt.show() # ## Recomputing expected return, volatility and Sharpe ratio # **Note**: When doing so, the instance variables for # - Expected return # - Volatility # - Sharpe Ratio # are automatically recomputed. # If the return, volatility and Sharpe ratio need to be computed based # on a different time window and/or risk free rate, one can recompute # those values as shown below # 1. set the new value(s) pf.freq = 100 pf.risk_free_rate = 0.02 # 2.a compute and get new values based on new freq/risk_free_rate exret = pf.comp_expected_return(freq=100) vol = pf.comp_volatility(freq=100) sharpe = pf.comp_sharpe() print( "For {} trading days and a risk free rate of {}:".format(pf.freq, pf.risk_free_rate) ) print("Expected return: {:0.3f}".format(exret)) print("Volatility: {:0.3f}".format(vol)) print("Sharpe Ratio: {:0.3f}".format(sharpe)) # 2.b print out properties of portfolio (which is based on new freq/risk_free_rate) pf.properties() # ## Extracting data of stocks individually # Each stock (its information and data) of the portfolio is stored as a Stock data structure. If needed, one can of course extract the relevant data from the portfolio DataFrame, or access the Stock instance. The commands are very similar to the once for Portfolio. See below how it can be used. # getting Stock object from portfolio, for Google's stock goog = pf.get_stock("WIKI/GOOG") # getting the stock prices goog_prices = goog.data print(goog_prices.head(3)) print(goog.comp_daily_returns().head(3)) print(goog.expected_return) print(goog.volatility) print(goog.skew) print(goog.kurtosis) print(goog) goog.properties() # ## Extracting stock data by date # Since quandl provides a DataFrame with an index of dates, it is easy to extract data from the portfolio for a given time frame. Three examples are shown below. print(pf.data.loc[str(datetime.datetime(2015, 1, 2))]) print(pf.data.loc[pf.data.index > datetime.datetime(2016, 1, 2)].head(3)) print(pf.data.loc[pf.data.index.year == 2017].head(3)) 

## Optimisation of a portfolio¶

This example focusses on the optimisation of a portfolio. To achieve this, the example shows the usage of finquant.efficient_frontier.EfficientFrontier for numerically optimising the portfolio, for the

• Minimum Volatility
• Maximum Sharpe Ratio
• Minimum Volatility for a given target Return
• Maximum Sharpe Ratio for a given target Volatility.

Furthermore, it is also shown how the entire Efficient Frontier and the optimal portfolios can be computed and visualised. If needed, it also gives an example of plotting the individual stocks of the given portfolio within the computed Efficient Frontier.

Also, the optimisation of a portfolio and its visualisation based on a Monte Carlo is shown.

Finally, FinQuant’s visualisation methods allow for overlays, if this is desired. Thus, with only the following few lines of code, one can create an overlay of the Monte Carlo run, the Efficient Frontier, its optimised portfolios for Minimum Volatility and Maximum Sharpe Ratio, as well as the portfolio’s individual stocks.

Note

This example refers to example/Example-Optimisation.py of the GitHub repository. It can be downloaded with jupyter notebook cell information: download Example-Optimisation.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 # # Example: Portfolio optimisation # This example shows how FinQuant can be used to optimise a portfolio. # Two different approaches are implemented in FinQuant: # 1. Efficient Frontier # 2. Monte Carlo run # With the *Efficient Frontier* approach, the 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 performing a numerical solve to minimise/maximise an objective function. # Alternatively a *Monte Carlo* run of n trials can be performed to find the optimal portfolios for # - minimum volatility, # - maximum Sharpe ratio # The approach branded as *Efficient Frontier* should be the preferred method for reasons of computational effort and accuracy. The latter approach is only included for the sake of completeness, and creation of beautiful plots. # # ## Visualisation # Not only does FinQuant allow for the optimisation of a portfolio with the above mentioned methods and objectives, FinQuant also allows for the computation and visualisation of an *Efficient Frontier* and *Monte Carlo* run. # Let pf be an instance of Portfolio. The *Efficient Frontier* can be computed and visualised with pf.ef_plot_efrontier(). The optimal portfolios for *minimum volatility* and *maximum Sharpe ratio* can be visualised with pf.ef_plot_optimal_portfolios(). And if required, the individual stocks of the portfolio can be visualised with pf.plot_stocks(show=False). An overlay of these three commands is shown below. # Finally, the entire result of a *Monte Carlo* run can also be visualised automatically by FinQuant. An example is shown below. import pathlib import matplotlib.pyplot as plt import numpy as np import pandas as pd import datetime # importing FinQuant's function to automatically build the portfolio from finquant.portfolio import build_portfolio # ### Get data from disk/file # Here we use pandas.read_cvs() method to read in the data. # stock data was previously pulled from quandl and stored in ex1-stockdata.csv # read data from files: df_data_path = pathlib.Path.cwd() / ".." / "data" / "ex1-stockdata.csv" df_data = pd.read_csv(df_data_path, index_col="Date", parse_dates=True) # building a portfolio by providing stock data pf = build_portfolio(data=df_data) print(pf) pf.properties() # # Portfolio optimisation # ## Efficient Frontier # Based on the **Efficient Frontier**, the portfolio can be optimised for # - minimum volatility # - maximum Sharpe ratio # - minimum volatility for a given target return # - maximum Sharpe ratio for a given target volatility # See below for an example for each optimisation. # if needed, change risk free rate and frequency/time window of the portfolio print("pf.risk_free_rate = {}".format(pf.risk_free_rate)) print("pf.freq = {}".format(pf.freq)) pf.ef_minimum_volatility(verbose=True) # optimisation for maximum Sharpe ratio pf.ef_maximum_sharpe_ratio(verbose=True) # minimum volatility for a given target return of 0.26 pf.ef_efficient_return(0.26, verbose=True) # maximum Sharpe ratio for a given target volatility of 0.22 pf.ef_efficient_volatility(0.22, verbose=True) # ### Manually creating an instance of EfficientFrontier # If required, or preferred, the below code shows how the same is achieved by manually creating an instance of EfficientFrontier, passing it the mean returns and covariance matrix of the previously assembled portfolio. from finquant.efficient_frontier import EfficientFrontier # creating an instance of EfficientFrontier ef = EfficientFrontier(pf.comp_mean_returns(freq=1), pf.comp_cov()) # optimisation for minimum volatility print(ef.minimum_volatility()) # printing out relevant quantities of the optimised portfolio (expected_return, volatility, sharpe) = ef.properties(verbose=True) # ### Computing and visualising the Efficient Frontier # FinQuant offers several ways to compute the *Efficient Frontier*. # 1. Through the opject pf # - with automatically setting limits of the *Efficient Frontier* # 2. By manually creating an instance of EfficientFrontier and providing the data from the portfolio # - with automatically setting limits of the *Efficient Frontier* # - by providing a range of target expected return values # As before, let pf and be an instance of Portfolio. The following code snippets compute and plot an *Efficient Frontier* of a portfolio, its optimised portfolios and individual stocks within the portfolio. # - pf.ef_plot_efrontier() # - pf.ef_plot_optimal_portfolios() # - pf.plot_stocks() # #### Efficient Frontier of pf # computing and plotting efficient frontier of pf pf.ef_plot_efrontier() # adding markers to optimal solutions pf.ef_plot_optimal_portfolios() # and adding the individual stocks to the plot pf.plot_stocks() plt.show() # #### Manually creating an Efficient Frontier with target return values targets = np.linspace(0.12, 0.45, 50) # computing efficient frontier efficient_frontier = ef.efficient_frontier(targets) # plotting efficient frontier ef.plot_efrontier() # adding markers to optimal solutions pf.ef.plot_optimal_portfolios() # and adding the individual stocks to the plot pf.plot_stocks() plt.show() # ## Monte Carlo # Perform a Monte Carlo run to find the portfolio with the minimum volatility and maximum Sharpe Ratio. opt_w, opt_res = pf.mc_optimisation(num_trials=5000) pf.mc_properties() pf.mc_plot_results() # again, the individual stocks can be added to the plot pf.plot_stocks() plt.show() print(opt_res) print() print(opt_w) # # Optimisation overlay # ## Overlay of Monte Carlo portfolios and Efficient Frontier solutions opt_w, opt_res = pf.mc_optimisation(num_trials=5000) pf.mc_plot_results() pf.ef_plot_efrontier() pf.ef.plot_optimal_portfolios() pf.plot_stocks() plt.show()