Examples

For more information about the project and details on how to use it, please look at the examples discussed below.

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# # Building a portfolio with data from `quandl`/`yfinance`
 2# ## Building a portfolio with `build_portfolio()` by downloading relevant data through `quandl`/`yfinance` with stock names, start and end date and column labels
 3# This example only focuses on how to use `build_portfolio()` to get an instance of `Portfolio` by providing a few items of 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`.
 4
 5import datetime
 6
 7import pandas as pd
 8
 9# importing some custom functions/objects
10from finquant.portfolio import build_portfolio
11
12# ## Get data from `quandl`/`yfinance` and build portfolio
13# 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.
14
15# To play around yourself with different stocks, here is a short list of companies and their tickers on Yahoo Finance:
16# d = {0: {'Name':'GOOG', 'Allocation':20},  # Google
17#      1: {'Name':'AMZN', 'Allocation':33},  # Amazon
18#      2: {'Name':'MSFT', 'Allocation':18},  # Microsoft
19#      3: {'Name':'AAPL', 'Allocation':10},  # Apple
20#      4: {'Name':'KO', 'Allocation':15},    # Coca-Cola
21#      5: {'Name':'XOM', 'Allocation':11},   # Exxon Mobil
22#      6: {'Name':'JPM', 'Allocation':21},   # JP Morgan
23#      7: {'Name':'DIS', 'Allocation':9},    # Disney
24#      8: {'Name':'MCD', 'Allocation':23},   # McDonald's
25#      9: {'Name':'WMT', 'Allocation':3},    # Walmart
26#     10: {'Name':'GS', 'Allocation':9},     # Goldman Sachs
27#     }
28
29d = {
30    0: {"Name": "GOOG", "Allocation": 20},
31    1: {"Name": "AMZN", "Allocation": 10},
32    2: {"Name": "MCD", "Allocation": 15},
33    3: {"Name": "DIS", "Allocation": 18},
34}
35# If you wish to use `quandl` as source, you must add "WIKI/" at the beginning of stock names/tickers, as "WIKI/GOOG".
36
37pf_allocation = pd.DataFrame.from_dict(d, orient="index")
38
39# ### User friendly interface to quandl/yfinance
40# As mentioned above, in this example `build_portfolio()` is used to build a portfolio by performing a query to `quandl`/`yfinance`. We mention that `quandl` will be removed in future versions of `FinQuant` as it is deprecated.
41#
42# To download Google's stock data, `quandl` requires the string `"WIKI/GOOG"` and `yfinance` the string `"GOOG"`.
43# 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.
44# For example, if using `quandl` as a data source (currently the default option), a list of names/tickers as shown below is a valid input for `FinQuant`'s function `build_portfolio(names=names)`:
45#  * `names = ["WIKI/GOOG", "WIKI/AMZN"]`
46#
47# 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):
48#  * `names = ["GOOG", "AMZN"]`
49#
50# By default, `FinQuant` currently uses `quandl` to obtain stock price data. The function `build_portfolio()` can be called with the optional argument `data_api` to use `yfinance` instead:
51#  * `build_portfolio(names=names, data_api="yfinance")`
52#
53# In the below example we are using `yfinance` to download stock data. We specify the start and end date of the stock prices to be downloaded.
54# We also provide the optional parameter `market_index` to download the historical data of a market index.
55# `FinQuant` can use them to calculate the Treynor Ratio, beta parameter, and R squared coefficient, measuring the portfolio's daily volatility compared to the market.
56
57# here we set the list of names based on the names in
58# the DataFrame pf_allocation
59names = pf_allocation["Name"].values.tolist()
60
61# dates can be set as datetime or string, as shown below:
62start_date = datetime.datetime(2015, 1, 1)
63end_date = "2017-12-31"
64
65# the market index used to compare the portfolio to (in this case S&P 500).
66# If the parameter is omitted, no market comparison will be done
67market_index = "^GSPC"
68
69# While quandl/yfinance will download lots of different prices for each stock,
70# e.g. high, low, close, etc, FinQuant will extract the column "Adj. Close" ("Adj Close" if using yfinance).
71
72pf = build_portfolio(
73    names=names,
74    pf_allocation=pf_allocation,
75    start_date=start_date,
76    end_date=end_date,
77    data_api="yfinance",
78    market_index=market_index,
79)
80
81# ## Portfolio is successfully built
82# Getting data from the portfolio
83
84# the portfolio information DataFrame
85print(pf.portfolio)
86
87# the portfolio stock data, prices DataFrame
88print(pf.data.head(3))
89
90# print out information and quantities of given portfolio
91print(pf)
92pf.properties()
93
94# ## Please continue with `Example-Build-Portfolio-from-file.py`.
95# 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# # Building a portfolio with data from disk
 2# ## Building a portfolio with `build_portfolio()` with data obtained from data files.
 3# Note: The stock data is provided in two data files. The stock data was previously pulled from quandl.
 4
 5import datetime
 6import pathlib
 7
 8import pandas as pd
 9
10# importing FinQuant's function to automatically build the portfolio
11from finquant.portfolio import build_portfolio
12
13# ### Get data from disk/file
14# Here we use `pandas.read_cvs()` method to read in the data.
15
16# stock data was previously pulled from quandl and stored in ex1-stockdata.csv
17# commands used to save data:
18# pf.portfolio.to_csv("ex1-portfolio.csv", encoding='utf-8', index=False, header=True)
19# pf.data.to_csv("ex1-stockdata.csv", encoding='utf-8', index=True, index_label="Date")
20# read data from files:
21df_pf_path = pathlib.Path.cwd() / ".." / "data" / "ex1-portfolio.csv"
22df_data_path = pathlib.Path.cwd() / ".." / "data" / "ex1-stockdata.csv"
23df_pf = pd.read_csv(df_pf_path)
24df_data = pd.read_csv(df_data_path, index_col="Date", parse_dates=True)
25
26# ### Examining the DataFrames
27
28print(df_pf)
29
30print(df_data.head(3))
31
32# ## Building a portfolio with `build_portfolio()`
33# `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.
34# In this example `build_portfolio()` is being passed `df_data`, which was read in from file above.
35
36print(build_portfolio.__doc__)
37
38# ## Building a portfolio with data only
39# 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.
40
41# building a portfolio by providing stock data
42pf = build_portfolio(data=df_data)
43
44# ### Portfolio is successfully built
45# 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`.
46
47# the portfolio information DataFrame
48print(pf.portfolio.name)
49print(pf.portfolio)
50
51# the portfolio stock data, prices DataFrame
52print(pf.data.head(3))
53
54# ## Building a portfolio with data and desired allocation
55# 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.
56
57# building a portfolio by providing stock data
58# and a desired allocation
59pf2 = build_portfolio(data=df_data, pf_allocation=df_pf)
60
61# the portfolio information DataFrame
62print(pf2.portfolio.name)
63print(pf2.portfolio)
64
65# the portfolio stock data, prices DataFrame
66print(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# # Example:
  2# ## Building a portfolio with `build_portfolio()` with data obtained from data files.
  3# Note: The stock data is provided in two data files. The stock data was previously pulled from quandl.
  4
  5import datetime
  6import pathlib
  7
  8import matplotlib.pyplot as plt
  9import pandas as pd
 10
 11# importing FinQuant's function to automatically build the portfolio
 12from finquant.portfolio import build_portfolio
 13
 14# ## Building a portfolio with `build_portfolio()`
 15# As in previous example, using `build_portfolio()` to generate an object of `Portfolio`.
 16
 17# read data from files:
 18df_data_path = pathlib.Path.cwd() / ".." / "data" / "ex1-stockdata.csv"
 19df_data = pd.read_csv(df_data_path, index_col="Date", parse_dates=True)
 20# building a portfolio by providing stock data
 21pf = build_portfolio(data=df_data)
 22
 23# ## Expected Return, Volatility, Sharpe Ratio, Sortino Ratio, and Value at Risk of Portfolio
 24# The annualised expected return and volatility, as well as the Sharpe Ratio, the Sortino Ratio, and Value at Risk are automatically computed.
 25# They are obtained as shown below.
 26# The expected return and volatility are based on 252 trading days by default.
 27# The Sharpe Ratio and the Sortino ratio are computed with a risk free rate of 0.005 by default.
 28# The Value at Risk is computed with a confidence level of 0.95 by default.
 29
 30# expected (annualised) return
 31print(pf.expected_return)
 32
 33# volatility
 34print(pf.volatility)
 35
 36# Sharpe Ratio (computed with a risk free rate of 0.005 by default)
 37print(pf.sharpe)
 38
 39# Sortino Ratio (computed with a risk free rate of 0.005 by default)
 40print(pf.sortino)
 41
 42# Value at Risk (computed with a confidence level of 0.95 by default)
 43print(pf.var)
 44
 45# ## Getting Skewness and Kurtosis of the stocks
 46
 47print(pf.skew)
 48
 49print(pf.kurtosis)
 50
 51# ## Nicely printing out portfolio quantities
 52# To print the expected annualised return, volatility, Sharpe Ratio, Sortino Ratio, skewness and Kurtosis of the portfolio and its stocks, one can simply do `pf.properties()`.
 53
 54print(pf)
 55pf.properties()
 56
 57# ## Daily returns and log returns
 58# `FinQuant` provides functions to compute daily returns and annualised mean returns of a given DataFrame in various ways.
 59
 60# annualised mean returns
 61print(pf.comp_mean_returns())
 62
 63# daily returns (percentage change)
 64print(pf.comp_cumulative_returns().head(3))
 65
 66print(pf.comp_daily_log_returns().head(3))
 67
 68# plotting stock data of portfolio
 69pf.data.plot()
 70plt.show()
 71
 72# 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.
 73
 74pf.data.plot(secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True)
 75plt.show()
 76
 77# plotting cumulative returns (price_{t} - price_{t=0}) / price_{t=0}
 78pf.comp_cumulative_returns().plot().axhline(y=0, color="black", lw=3)
 79plt.show()
 80
 81# plotting daily percentage changes of returns
 82pf.comp_daily_returns().plot().axhline(y=0, color="black")
 83plt.show()
 84
 85# plotting daily log returns
 86pf.comp_daily_log_returns().plot().axhline(y=0, color="black")
 87plt.show()
 88
 89# cumulative log returns
 90pf.comp_daily_log_returns().cumsum().plot().axhline(y=0, color="black")
 91plt.show()
 92
 93# ## Moving Averages
 94# `FinQuant` provides a module `finquant.moving_average` to compute moving averages. See below.
 95
 96from finquant.moving_average import sma
 97
 98# simple moving average
 99ax = pf.data.plot(secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True)
100# computing simple moving average over a span of 50 (trading) days
101# and plotting it
102sma(pf.data, span=50).plot(ax=ax, secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True)
103plt.show()
104
105from finquant.moving_average import ema
106
107# exponential moving average
108ax = pf.data.plot(secondary_y=["WIKI/MCD", "WIKI/DIS"], grid=True)
109# computing exponential moving average and plotting it
110ema(pf.data).plot(ax=ax, secondary_y=["WIKI/MCD", "WIKI/DIS"])
111plt.show()
112
113# ## Band of moving averages and Buy/Sell signals
114# `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.
115# To learn more about it and its input arguments, read its docstring and see the example below.
116
117from finquant.moving_average import compute_ma
118
119print(compute_ma.__doc__)
120
121# get stock data for disney
122dis = pf.get_stock("WIKI/DIS").data.copy(deep=True)
123# we want moving averages of 10, 50, 100, and 200 days.
124spans = [10, 50, 100, 150, 200]
125# compute and plot moving averages
126dis_ma = compute_ma(dis, ema, spans, plot=True)
127plt.show()
128
129# ## Plot the Bollinger Band of one stock
130# The Bollinger Band can be automatically computed and plotted with the method `finquant.moving_average.plot_bollinger_band`. See below for an example.
131
132# plot the bollinger band of the disney stock prices
133from finquant.moving_average import plot_bollinger_band
134
135# get stock data for disney
136dis = pf.get_stock("WIKI/DIS").data.copy(deep=True)
137span = 20
138# for simple moving average:
139plot_bollinger_band(dis, sma, span)
140plt.show()
141# for exponential moving average:
142plot_bollinger_band(dis, ema, span)
143plt.show()
144
145# ## Recomputing expected return, volatility and Sharpe ratio
146# **Note**: When doing so, the instance variables for
147#  - Expected return
148#  - Volatility
149#  - Sharpe Ratio
150# are automatically recomputed.
151
152# If the return, volatility and Sharpe ratio need to be computed based
153# on a different time window and/or risk free rate, one can recompute
154# those values as shown below
155# 1. set the new value(s)
156pf.freq = 100
157pf.risk_free_rate = 0.02
158
159# 2.a compute and get new values based on new freq/risk_free_rate
160exret = pf.comp_expected_return(freq=100)
161vol = pf.comp_volatility(freq=100)
162sharpe = pf.comp_sharpe()
163print(
164    "For {} trading days and a risk free rate of {}:".format(pf.freq, pf.risk_free_rate)
165)
166print("Expected return: {:0.3f}".format(exret))
167print("Volatility: {:0.3f}".format(vol))
168print("Sharpe Ratio: {:0.3f}".format(sharpe))
169
170# 2.b print out properties of portfolio (which is based on new freq/risk_free_rate)
171pf.properties()
172
173# ## Extracting data of stocks individually
174# 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.
175
176# getting Stock object from portfolio, for Google's stock
177goog = pf.get_stock("WIKI/GOOG")
178# getting the stock prices
179goog_prices = goog.data
180print(goog_prices.head(3))
181
182print(goog.comp_daily_returns().head(3))
183
184print(goog.expected_return)
185
186print(goog.volatility)
187
188print(goog.skew)
189
190print(goog.kurtosis)
191
192print(goog)
193goog.properties()
194
195# ## Extracting stock data by date
196# 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.
197
198print(pf.data.loc[str(datetime.datetime(2015, 1, 2))])
199
200print(pf.data.loc[pf.data.index > datetime.datetime(2016, 1, 2)].head(3))
201
202print(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# # Example: Portfolio optimisation
  2# This example shows how `FinQuant` can be used to optimise a portfolio.
  3# Two different approaches are implemented in `FinQuant`:
  4#  1. Efficient Frontier
  5#  2. Monte Carlo run
  6# With the *Efficient Frontier* approach, the portfolio can be optimised for
  7#  - minimum volatility,
  8#  - maximum Sharpe ratio
  9#  - minimum volatility for a given expected return
 10#  - maximum Sharpe ratio for a given target volatility
 11# by performing a numerical solve to minimise/maximise an objective function.
 12# Alternatively a *Monte Carlo* run of `n` trials can be performed to find the optimal portfolios for
 13#  - minimum volatility,
 14#  - maximum Sharpe ratio
 15# 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.
 16#
 17# ## Visualisation
 18# 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.
 19# 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.
 20# Finally, the entire result of a *Monte Carlo* run can also be visualised automatically by `FinQuant`. An example is shown below.
 21
 22import datetime
 23import pathlib
 24
 25import matplotlib.pyplot as plt
 26import numpy as np
 27import pandas as pd
 28
 29# importing FinQuant's function to automatically build the portfolio
 30from finquant.portfolio import build_portfolio
 31
 32# ### Get data from disk/file
 33# Here we use `pandas.read_cvs()` method to read in the data.
 34
 35# stock data was previously pulled from quandl and stored in ex1-stockdata.csv
 36# read data from files:
 37df_data_path = pathlib.Path.cwd() / ".." / "data" / "ex1-stockdata.csv"
 38df_data = pd.read_csv(df_data_path, index_col="Date", parse_dates=True)
 39# building a portfolio by providing stock data
 40pf = build_portfolio(data=df_data)
 41print(pf)
 42pf.properties()
 43
 44# # Portfolio optimisation
 45# ## Efficient Frontier
 46# Based on the **Efficient Frontier**, the portfolio can be optimised for
 47#  - minimum volatility
 48#  - maximum Sharpe ratio
 49#  - minimum volatility for a given target return
 50#  - maximum Sharpe ratio for a given target volatility
 51# See below for an example for each optimisation.
 52
 53# if needed, change risk free rate and frequency/time window of the portfolio
 54print("pf.risk_free_rate = {}".format(pf.risk_free_rate))
 55print("pf.freq = {}".format(pf.freq))
 56
 57pf.ef_minimum_volatility(verbose=True)
 58
 59# optimisation for maximum Sharpe ratio
 60pf.ef_maximum_sharpe_ratio(verbose=True)
 61
 62# minimum volatility for a given target return of 0.26
 63pf.ef_efficient_return(0.26, verbose=True)
 64
 65# maximum Sharpe ratio for a given target volatility of 0.22
 66pf.ef_efficient_volatility(0.22, verbose=True)
 67
 68# ### Manually creating an instance of EfficientFrontier
 69# 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.
 70
 71from finquant.efficient_frontier import EfficientFrontier
 72
 73# creating an instance of EfficientFrontier
 74ef = EfficientFrontier(pf.comp_mean_returns(freq=1), pf.comp_cov())
 75# optimisation for minimum volatility
 76print(ef.minimum_volatility())
 77
 78# printing out relevant quantities of the optimised portfolio
 79(expected_return, volatility, sharpe) = ef.properties(verbose=True)
 80
 81# ### Computing and visualising the Efficient Frontier
 82# `FinQuant` offers several ways to compute the *Efficient Frontier*.
 83#  1. Through the opject `pf`
 84#   - with automatically setting limits of the *Efficient Frontier*
 85#  2. By manually creating an instance of `EfficientFrontier` and providing the data from the portfolio
 86#   - with automatically setting limits of the *Efficient Frontier*
 87#   - by providing a range of target expected return values
 88# 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.
 89#  - `pf.ef_plot_efrontier()`
 90#  - `pf.ef_plot_optimal_portfolios()`
 91#  - `pf.plot_stocks()`
 92
 93# #### Efficient Frontier of `pf`
 94
 95# computing and plotting efficient frontier of pf
 96pf.ef_plot_efrontier()
 97# adding markers to optimal solutions
 98pf.ef_plot_optimal_portfolios()
 99# and adding the individual stocks to the plot
100pf.plot_stocks()
101plt.show()
102
103# #### Manually creating an Efficient Frontier with target return values
104
105targets = np.linspace(0.12, 0.45, 50)
106# computing efficient frontier
107efficient_frontier = ef.efficient_frontier(targets)
108# plotting efficient frontier
109ef.plot_efrontier()
110# adding markers to optimal solutions
111pf.ef.plot_optimal_portfolios()
112# and adding the individual stocks to the plot
113pf.plot_stocks()
114plt.show()
115
116# ## Monte Carlo
117# Perform a Monte Carlo run to find the portfolio with the minimum volatility and maximum Sharpe Ratio.
118
119opt_w, opt_res = pf.mc_optimisation(num_trials=5000)
120pf.mc_properties()
121pf.mc_plot_results()
122# again, the individual stocks can be added to the plot
123pf.plot_stocks()
124plt.show()
125
126print(opt_res)
127print()
128print(opt_w)
129
130# # Optimisation overlay
131# ## Overlay of Monte Carlo portfolios and Efficient Frontier solutions
132
133opt_w, opt_res = pf.mc_optimisation(num_trials=5000)
134pf.mc_plot_results()
135pf.ef_plot_efrontier()
136pf.ef.plot_optimal_portfolios()
137pf.plot_stocks()
138plt.show()