SSRN 4758848
SSRN 4758848
ABSTRACT
This article proposes an interactive framework for teaching the modern portfolio theory
with Python. The course material is suitable for advanced bachelor and entry master-level
courses in investments, offering a step-by-step tutorial of the data-driven quantitative
investment process. Students will learn to apply portfolio choice models to market data
and develop essential programming skills through data collection, input estimation, con-
straint imposition, portfolio optimization, back-testing, implementation, and performance
evaluation. By emphasizing the importance of realism, this teaching framework highlights
the potential pitfalls and fallacies when applying financial theories blindly.
∗
E-mail address: cltd@nccu.edu.tw.
This article provides a step-by-step guide on using Python to teach the Markowitz
(1952) modern portfolio theory (MPT) interactively. It is imperative to modernize the way
we teach finance. Root, Rozycki, Senteza, and Suh (2007) surveyed the undergraduate
finance programs in 655 institutions, and they found that most finance curricula were
slow to reflect recent trends in the financial industry. Nowadays, standard textbooks
(Bodie, Kane, and Marcus, 2021, 2022) in undergraduate and MBA curricula mainly cover
two risky assets in their expositions of the portfolio theory. By considering only two
risky assets, it greatly simplifies the mathematics required and helps students gain an
intuitive understanding of efficient diversification. However, if the teaching material does
not go beyond two assets, students will feel disconnected as they do not know how to
implement what they learned in the stock market. Therefore, this article fills the gap
between portfolio theory and quantitative investment practices.
The primary goal of teaching with Python is to acquaint students with programming
techniques in portfolio analysis. Programming skills will be valuable assets for finance
graduates in the age of big data. The Economist (2017) argues that data has replaced
oil in becoming the world’s most valuable resource. According to Alexander (2022), data
scientists are highly sought after by Wall Street. Business schools are revamping their
curricula to equip their students with skill sets relevant to the data-driven economy.
Patrick Kandawire, the deputy chief operating officer for capital markets at Morgan
Stanley, said, “I would say for the next generation, take the Python course. Understand
where some of this technology is going,”.
According to the latest TIOBE (2023) Index, Python remains the most popular
programming language based on internet search volume. Python is free to use. Therefore,
many open-source Python resources are readily available to instructors and students
online. Hilpisch (2018) provides an excellent recipe book for people with programming
experience to learn finance applications in Python. However, it can be challenging for
finance majors and instructors without backgrounds in Python to learn and teach. This
article fills the gap by offering a step-by-step guide to teaching portfolio theory with a
companion JupyterLab Notebook. It is also structured to complement the interactive
Teaching portfolio theory with computer programs has a long history. Before
the prevalence of personal computers, Eckardt (1975, 1978) and Alexander (1978, 1981)
designed proprietary computer programs for teaching portfolio theory and management.
Runyon (1978), Nawrocki (1980), Riley and Montgomery (1980), Pfaff (1981), and
Burns and Burns (1982) advocated using computer simulations in classrooms to promote
realism by bridging portfolio theory with practical applications. Since the 1990s, personal
computers and spreadsheet tools have become readily available. Stephens (1998), Kwan
(2001), Carter, Dare, and Elliott (2002), and Johnson and Liu (2005) illustrated using
Excel spreadsheets to construct mean-variance efficient portfolios and frontier under
different constraints. Repeated experiments conducted by Cagle, Glasgo, and Hyland
(2010) showed that spreadsheet assignments were effective tools in helping students learn
finance.
However, Excel is not suitable for analyzing large data sets in the big data era. Excel
templates typically lack the flexibility for creating mean-variance portfolios with different
numbers of risky assets. Excel users often have to redesign and reconstruct the entire
spreadsheet to make significant changes. In other words, it is difficult to make scalable
programs in Excel. Teaching students Excel VBA is a potential solution (Bauer, 2006), but
it is a less popular language with limited open-source support. Moreover, Excel VBA still
cannot make Excel a practical tool for analyzing a large volume of data. Since teaching
programming to finance students is beneficial, why not choose a general-purpose language
like Python? Apart from the capacity to handle large data sets, there are many open-
source Python packages for downloading financial data through Application Programming
Interfaces (APIs), allowing instructors to demonstrate applications of financial models
with real-world data.
In addition to Python being a better tool for analyzing financial data, the JupyterLab
As pointed out by Markowitz (1990) in his Nobel Prize Lecture, the intuition
1
E[Up,A ] = E[rp ] − Aσp2 . (1)
2
For an investor with a risk aversion of A, the expected utility (E[Up,A ]) of a portfolio p
equals the ratio between the portfolio expected return (E[rp ]) and the product of the
risk aversion and the portfolio variance (σp2 ) divided by two. In reality, it does not
mean investors have quadratic utility functions. Instead, Markowitz views mean-variance
analysis as a practical solution to approximate the maximum expected utility (Kritzman
and Markowitz, 2017).
Following Arnold (2002), this article emphasizes the necessity of using linear
algebra in teaching portfolio theory. With linear algebra, instructors can demonstrate
real-world applications of portfolio choices beyond two risky assets. Moreover, numerical
optimizations of portfolio problems in Python require array (matrix) operations in NumPy
and SciPy. Using matrix notations, the portfolio variance for N risky assets is
w⊺ E[R]
SRp = √ , (3)
w⊺ Σw
where E[R] is a N × 1 vector of risky assets’ expected excess returns. Therefore, the
numerator is the portfolio expected excess return and the denominator is the portfolio
standard deviation. To find the Maximum Sharpe Ratio Portfolio (MSRP), the objective
function becomes the portfolio Sharpe Ratio (SRp ), and we maximize it by choosing w.
Portfolio weights must sum up to one. The equality investment constraint is thus w⊺ 1 = 1,
with 1 being a N × 1 vector of ones. By imposing the equality investment constraint, the
Σ−1 1
wg = (4)
1⊺ Σ−1 1
and
Σ−1 E[R]
wm = , (5)
1⊺ Σ−1 E[R]
respectively. Both portfolios are independent of investors’ risk aversions and on the
efficient minimum variance frontier without the risk-free asset. If investors can borrow or
lend at the common risk-free rate, the theoretical efficient frontier becomes the capital
allocation line linking between MSRP and the risk-free asset. If we maximize the expected
mean-variance utility function in Equation (3), we obtain
Σ−1 1 −1 −1
h 1⊺ Σ−1 E[R] i
wa = + A Σ E[R] − 1 . (6)
1⊺ Σ−1 1 1⊺ Σ−1 1
The optimal risky portfolio for an investor is thus the sum of the GMVP and a zero-
sum portfolio that depends on the investor-specific risk aversion. For advanced-level
courses, instructors can derive these closed-form solutions with vector calculus and explain
their implications. However, analytical solutions for portfolio choice problems are no
longer available when we introduce inequality or nonlinear constraints. To find admissible
solutions for the quadratic programming problem subject to realistic investment constraints,
we will numerically solve the system of equations and inequalities corresponding to the
Karush–Kuhn–Tucker (KKT) conditions with Python.
JUPYTERLAB NOTEBOOK
In step two, we define our investment universe by enclosing stock tickers in a list:
[‘PG’, ‘DIS’, ‘IBM’, ‘NKE’, ‘BA’, ‘KO’, ‘CVX’] with square brackets. These seven
stocks are BA (Boeing), CVX (Chevron), Coca-Cola (KO), DIS (Disney), IBM (IBM),
NKE (Nike), and PG (Procter & Gamble). Instructors should encourage students to
experiment with different stocks across global stock markets. We use the download
function from yfinance to download daily stock data from Yahoo! Finance. The first input
to the function is the list containing tickers, followed by data frequency in interval, start
date in start, and end date in end. The resulting output is a table (pandas data frame)
named Ast, which contains multiple items for seven stocks from 1 December 2017 to 29
September 2023. We subset the Ast table with the column name ‘Adj Close’ to get the
adjusted closing prices, which are the closing prices after all applicable adjustments for
stock splits and dividend payments. Before going through the code further, instructors
should discuss the dichotomy between the in-sample period for constructing the optimal
portfolio and the out-of-sample period for back-testing the investment strategy. Figure
1 presents a timeline for using five data periods to estimate the portfolio and one data
period to test the strategy. It is essential to emphasize that the IS period must not
overlap with the out-of-sample period to avoid look-ahead bias in back-testing investment
performance. In other words, we cannot use future information in making investment
Figure 1: Back-testing
Estimate Test
Period
−5 −4 −3 −2 −1 0 1
When estimating inputs for the portfolio model, we use the convention sampling
window of 60 monthly returns (5 years of data). Therefore, we apply the loc method
to subset the data by its row index labels. The input of [:‘2022-12-29’] means our
in-sample period starts with the first row until the row of 29 December 2022. Next, we
use resample(‘M’).last() to convert the in-sample daily adjusted closing prices into the
month-end prices. We then convert these adjusted closing prices into percentage returns
with the pct_change() method. Instructors should remind students that these computed
returns only reflect capital gain or loss because percentage changes based on the adjusted
closing prices do not account for dividend yields. The percentage change calculation
requires two consecutive prices, so the first row of the resulting Ri table contains missing
values. We remove them using the dropna() method. We can apply multiple methods to
transform the original object into the desired output with a single line of code. If students
are new to programming, instructors can consider breaking the chain into multiple steps
to explain the inner workings of the code better. For instance, one can create the subset
of Ast by AstIS = Ast[‘Adj Close’].loc[:‘2022-12-29’] and convert it into month-end
data by AstIS = AstIS.resample(‘M’).last().
As for the out-of-sample back-testing period, we again subset Ast with loc to
create the CRo table. We compute the cumulative gross returns of all seven stocks at a
In step four, we use NumPy arrays and SciPy functions to estimate four portfolios:
i). G: Global Minimum Variance Portfolio (GMVP); ii). M: Maximum Sharpe Ratio
Portfolio (MSRP); iii). Gn: GMVP with no short selling; and iv). Mn: MSRP with no
short selling. Before using the minimize function, we must specify the initial guess for
portfolio weights and investment constraints. We use the len function to count the number
of elements in ER to get the number of assets N. Alternatively, we can use Ri.shape to
check the dimensions of Ri, which returns a tuple containing the number of rows in the
first element and the number of columns in the second element. Please note that shape is
an attribute of the data frame, not a pandas method. If one writes Ri.shape(), an error
will arise. Given our initial guess x0 of an equal-weighted portfolio, we divide an array
of N ones by N. The first investment constraint is an equality constraint ‘type’: ’eq’
with the sum of portfolio weights minus one equals zero ‘fun’: lambda x: np.sum(x) -
1. The lambda function takes an array x as input and returns the sum of elements in
x minus one. We have to specify this constraint inside a dictionary { }. Similar to the
aforementioned list [ ] and tuple ( ,), the dictionary is a built-in data structure of Python.
After preparing all the ingredients for constrained optimizations, we can go through the
procedure of solving the four portfolios individually.
[4]: N = len(ER)
x0 = np.ones(N)/N # initial guess with w = 1/N
cons = ({'type': 'eq', 'fun' : lambda x: np.sum(x) - 1})
10
M: The inputs for estimating M are similar to G, except for changing the objective
function to NPSR and supplying additional arguments args=(ER, S) to the objec-
tive function. In other words, the optimization problem becomes the minimization
of the portfolio Sharpe Ratio.
Gn: The Bounds function allows us to define the possible range for individual asset
weights wi . It precludes short selling by restricting the lower and upper bounds
to 0 and 1, respectively. These bounds are equivalent to having the inequality
constraint of 0 ≤ wi ≤ 1. Together with the inputs in estimating G, we further add
bounds=bounds to the minimize function to estimate Gn.
In the final step, we visualize our estimated portfolio weights with a bar plot. P is
an empty pandas data frame with stock tickers as row names index=Ri.columns and
the abbreviations of five portfolios as column names columns=[‘G’, ‘M’, ‘Gn’, ‘Mn’,
‘EW’]. We assign the four sets of portfolio weights estimated in the previous step into P
and plot them using P.plot(kind=‘bar’). All the plots in this cell use the ‘seaborn’
style. The additional Portfolio EW is an equal-weighted strategy that allocates 14.29%
into each stock (wi = 1/7).
[5]: plt.style.use('seaborn')
fig2a = P.plot(kind='bar')
fig2b = (CRo @ P).plot()
11
As shown in Figure 2a, both the global minimum variance portfolio G and the
maximum Sharpe Ratio portfolio M have short selling positions. Portfolio G shorts
6.1% only in Boeing while Portfolio M shorts 14.7% in Boeing, 33.8% in Disney, and
21.2% in IBM. Instructors should explain to students that the short positions in M are
unrealistic as they make the portfolio highly leveraged and very risky. In reality, Portfolio
M is also not implementable because its percentage margin of 41.8% violates the Federal
Reserve Board Regulation T’s minimum 50% initial margin. The percentage margin
is defined as equity divided by the sum of absolute markets values of long and short
positions in stocks. In our example, we compute the percentage margin of Portfolio M
by dividing the total invested cash of $1 by the total absolute weights in stocks. Luckett
(1988) explains the use of margin credit in investment and how the Federal Reserve can
mitigate market speculations by imposing a minimum margin requirement. After imposing
short-sale constraints, Portfolio Gn and Portfolio Mn have only positive weights but no
longer invest in every stock because negative weights in Portfolio G and Portfolio M are
essentially set to zero. For instance, Portfolio Mn invests 67.9% in Procter & Gamble
(SR = 0.23), 16.4% in Nike (SR = 0.18), and 15.7% in Chevron (SR = 0.15). This result
is hardly surprising as the optimizer aims to maximize the portfolio’s in-sample Sharpe
Ratio (SR = 0.27). Assuming zero risk-free rate, we can compute in-sample Sharpe Ratios
of assets by dividing their average returns by their standard deviations. The Python code
is Ri.mean()/Ri.std(). As for portfolio in-sample Sharpe Ratio, we can compute it with
the negative of the pre-specified NPSR function. For example, the code for calculating the
in-sample Sharpe Ratio for Portfolio G is -NPSR(G, ER, S). In contrast, Portfolio Gn
is more diversified, with positive weights in six out of seven stocks. Therefore, instructors
should highlight the potential concentration risk of choosing Portfolio Mn over Portfolio
12
To assess the performance of the four optimal portfolios, we compare the buy-and-
hold out-of-sample cumulative daily returns from January 2023 until October 2023 in
Figure 2b. Students should now become clear that maximizing the in-sample Sharpe
Ratio may not guarantee a good out-of-sample performance. Portfolio M had the highest
in-sample Sharpe Ratio (SR = 0.32), but it performed the worst out-of-sample. Because
of the high leverage ratio in Portfolio M, the path of its out-of-sample portfolio values
was more bumpy than the rest. In other words, investors of Portfolio M would have
experienced large drawdowns and volatile returns. On the contrary, Portfolios G, Gn,
and Mn held at least 40% in Procter & Gamble and 10% in Nike, and they had tiny or no
short-selling positions. Therefore, they exhibited similar patterns in cumulative returns
over the out-of-sample period.
In Figure 2b, the value of Portfolio EW was on top of others over most of the
out-of-sample period, revealing that more sophisticated portfolios from portfolio theory
might not always perform better than an agnostic strategy. This result might seem
surprising to students, who might question the necessity of learning portfolio theory. To
resolve the potential confusion for students, instructors should consider the following steps.
First, remind students that the back-testing result is always sample-specific. Given only
seven stocks in a short out-of-sample period, we need to include more stocks and use
longer samples to evaluate the empirical performance of these strategies.
13
highly volatile asset classes like small cap or emerging markets.” By imposing investment
constraints, we avoid extreme allocations and excessive leverages in our portfolios. There
is ample evidence showing that statistical adjustment of inputs and realistic investment
constraints enhance the out-of-sample performance of mean-variance-efficient portfolios.
Regarding input estimations, Jobson and Korkie (1981) consider the James-Stein
approach to estimate the expected returns of individual stocks by the cross-sectional
average of their historical average returns. Using the same estimate for individual stock
returns in portfolio optimization enhances the out-of-sample Sharpe Ratio of the MSRP.
Frost and Savarino (1986) and Jorion (1986) also apply Bayesian shrinkage estimators
on the sample mean. By shrinking sample average returns towards their proposed priors,
they select portfolios superior to those based on sample estimates. Similarly, Ledoit
and Wolf (2004, 2017) show that variance-covariance matrices estimated from shrinkage
estimators outperform their sample counterparts in portfolio optimizations. Since the goal
of the MSRP is to select stocks that maximize the portfolio Sharpe Ratio, the resulting
portfolio weights are sensitive to estimation error in expected returns. In line with this
view, Haugen and Baker (1991) find that the low-volatility portfolio generates superior
out-of-sample performance over the Wilshire 5000 index, whereas Green and Hollifield
(1992) argue using the GMVP to circumvent extreme portfolio allocations arising from
imprecise input estimates. Instructors can follow up by discussing the growing popularity
of low volatility investing (Blitz and van Vliet, 2007) in the asset management industry.
14
Third, as stated in Box (1979), “Models, of course, are never true, but fortunately it
is only necessary that they be useful”. There will always be a chasm between theory and
practice. However, models are essential in guiding us to analyze the problem systematically.
In our example, portfolios with low volatility, non-negativity constraints, or 1/N allocations
all perform better than the canonical maximum Sharpe Ratio portfolio. Therefore,
instructors should make students aware of new developments in applying portfolio theory
from both the practitioner and academic sides.
15
Finally, the standard caveat of “past performance does not guarantee future results”
will always apply to investment strategies based on historical data because of estimation
errors and non-stationary parameters. Since the future is hard to predict, the investment
policy statement must include risk warnings and disclaimers.
Regarding actual applications, some universities have the resources to allow their
students to manage real money portfolios. For example, Belt (1975) and Bear and Boyd
(1984) describe student-managed portfolio programs at their institutions. Yerkes (2018)
highlights key benefits and challenges in letting students manage actual funds. Moreover,
16
Impose Constraints
Portfolio Optimization
Back-testing
Implementation
Performance Evaluation
Lin (2022) explains why these funds face unique challenges and recommends ways of
tackling them. As a low-cost alternative, Wood, O’Hare, and Andrews (1992) discuss the
costs and benefits of using a stock market game with hypothetical money as an educational
tool in the classroom. Kagan, Mayo, and Stout (1995) point out that participants in
stock market games tend to take excessive risks in under-diversified portfolios. Jankowski
and Shank (2010) also argue that free online trading simulators lack the flexibility for
higher-level courses. That said, Ali, Derina, and Zurbruegg (2009) find that students
become more motivated to study and eager to pursue a future career in finance after
participating in an online portfolio trading game.
Therefore, when designing the portfolio theory course, instructors should adopt
the problem-based learning approach to offer a realistic experience to students (Loviscek,
Crowley, and Anderson, 2003). On the one hand, homework assignments should focus
on developing students’ technical skills in statistics and optimizations. Instructors can
specify a sample data set and provide expected outcomes for students to replicate. By
doing so, students can check their understanding of the course material and ensure
they are proficient with Python applications in portfolio selections. On the other hand,
group projects and presentations should focus on encouraging students’ creativity, critical
thinking, and collaboration. Table 1 gives a sample description of the group project.
Students can freely choose the investment universe, the statistical tools for estimating
inputs, and the portfolio construction methodology. The only constraints students face are
17
In December 2022, you are working with a group of fund managers managing a
quantitative fund. Your group wants to design and implement a new investment strategy
starting January 2023. Your investment decisions should be based on statistical
analysis and back-testing. The fund mandate is to explore profitable equity investment
opportunities in a stock market. The fund’s investors have moderate risk tolerance so
that the fund can take leveraged or short-selling positions. However, the fund’s initial
percentage margin must be higher than 50%. The fund’s model validation quant will
inspect your team’s source Python codes in constructing the strategy.
investors’ risk tolerance and the leverage limit, thus restricting excessive risk-taking and
under-diversification. By analyzing international stock markets, instructors can discuss
the equity home bias puzzle (French and Poterba, 1991) and explain the potential benefit
of diversifying investment globally. To promote data and knowledge sharing, students
must upload their Python codes and investment policy statements of their investment
strategies onto the class website before their project presentations. Students will learn
to work in a team and write professionally. The development of technical writing skill is
essential as Kish and Hogan (2001) suggest that write-ups in asset allocation exercises
help students prepare for job interviews. In the investment policy statement, students
must state their fund’s investment objectives to potential clients and explain why they
believe their strategy can meet their goals. Furthermore, they should discuss their fund’s
asset allocation, risk tolerance, and other practical concerns. Like academic conferences,
project groups will present their strategies and critique other groups’ findings. The peer
review process motivates students to think critically about each other’s work. At the end
of each presentation and discussion session, instructors should give their comments and
suggestions to student presenters and discussants. In between sessions, instructors should
open the floor for Q&As.
18
19
20
21
22