Skip to content

rtkg12/CS524-Financial-Optimization-Project

Repository files navigation

CS/ECE/ISyE 524 — Introduction to Optimization — Spring 2019

Equity Valuation and Portfolio Optimization Using Modern Portfolio Theory

Ritik Goyal (ragoyal2@wisc.edu), Cole Thomson (cthomson4@wisc.edu), Noah Dreikosen (njdreikosen@wisc.edu), and Zachary Easton (zeaston@wisc.edu)


Table of Contents

  1. Introduction
  2. Mathematical Model
  3. Equity Valuation Model
  4. Markowitz Modern Portfolio Model
  5. Solution
  6. Results and Discussion
  7. Standard Deviations and Expected Returns of Basket of Equities
  8. Optimal Portfolio Examples - Long Positions
  9. Optimal Portfolio Examples - Short Positions
  10. Pareto Frontier
  11. Accuracy of Models and Possible Improvements
  12. Conclusion
  13. References

1. Introduction

Approximately $169 billion dollars of stocks are traded daily on the New York Stock Exchange. The overall value of the companies traded in the U.S. stock market is $34 trillion. This equates to roughly 43% of the value of all publicly traded companies in the world (Surz, 2018). Millions of investors look to buy (sell) companies that they feel are undervalued (overvalued) so that they may sell (cover) their position at some later date for a profit. To do this, traders and investors must analyze thousands of stocks based on the expected risks and returns, which can be done many different ways. One such strategy that investors use, which will be examined in this project, combines Modern Portfolio Theory, introduced by economist Harry Markowitz, with Fundamental Analysis of the underlying factors that affect a stock's price - a method widely advocated by investing juggernauts like Benjamin Graham and Warren Buffett.

This project attempts to accomplish two main tasks. First, an absolute equity (stock) valuation model is to be developed that receives fundamental data of a company as parameters and returns the value of the company. The value returned by the model is assumed to be the intrinsic value of the company. This value can be compared to the market capitalization (or market value - as determined by the company’s stock price and number of outstanding shares) to determine if the stock is under, over, or fair-valued. Second, an optimal portfolio is to be developed using both the Markowitz Modern Portfolio Theory and the valuation determined by the previous model. Both long (buying securities) and short (selling securities by borrowing shares) optimal portfolios are discussed and explored.

Benjamin Graham, and his famed prodigy Warren Buffett, have forged their investment principles by leveraging fundamental characteristics (among a few other ideas) of a company to determine its actual value. Fundamental data is any data that is expected to affect the perceived value of an equity (McClure, 2019). Examples of fundamental data include: cash flow, return on assets, earnings, debt levels, and many more. In total, there were 74 fundamental metrics used to develop the equity valuation model described in this report. In this project, 1,230 samples were collected from years 2012 to 2016. Each of these samples are sourced from Form 10-K SEC filings that companies must submit to shareholders on a yearly basis. This dataset can be found on Kaggle, an open source data science community, from which both fundamental analysis and stock price data is taken.

Harry Markowitz developed what is now known as Modern Portfolio Theory (MPT) that was first published in The Journal of Finance in 1952 (Chen, 2019). The model has various assumptions not discussed in this report, but is rooted in the idea that choosing a group of investment equities which collectively have lower risk than any single equity will have on its on its own. Depending on investment goals, a tradeoff between the expected returns of a portfolio and the risk of the associated portfolio can be explored. An optimal portfolio lies on the Pareto frontier of expected returns and expected portfolio risk (Kenton, 2018). In this project, we explore the addition of a third tradeoff term to determine an optimal portfolio. This additional term is the amount undervalued (or overvalued) of an equity as determined by our equity valuation model. We explore different trade-offs to reflect different investment styles in this report.

In the coming sections mathematical models, solution code (in Julia 1.1.0), discussion of results, and the conclusion of this optimization project will be available.

2. Mathematical model

2.A. Equity Valuation Model

Type of Model: Least Squares Regression

Variables:

Weights of each fundamental attribute to determine the value of a company's stock:

Parameters:

Company i with fundamental attribute j:

Market capitalization of company i:

Constraints:

There exists no constraints for this model.

Objective:

We aim to find the curve that predicts the true value of a company based on the company's current fundamental data. To accomplish this, we set the objective to minimize the sum of squares between the companies' current market capitalization (y) and the market capitalization predicted by our model (B x u).

Full Model:

2.B. Markowitz Modern Portfolio Model

Type of Model: Quadratic Program

Variables:

Proportion of total portfolio to invest in equity i:

Parameters:

Expected daily return of equity i as a percentage:

Covariance between equity i and equity j (used to measure risk):

Percent difference between the estimated value of the company and the current market capitalization of the company (obtained from Equity Valuation Model):

Tradeoff weights for covariance matrix (risk) and the percent under/over valued determined by the Equity Valuation Model:

Constraints:

For Long Portfolio: The amount invested in each company must be non-negative, and no single investment may exceed 20% of the total portfolio:

The portfolio is allocated to 100% capacity:

For Short-only Portfolio:

The amount invested in each company must be non-positive, and no single investment may exceed 20% of the total portfolio:

The portfolio is allocated to 100% capacity:

Objective:

For a Long porfolio, we aim to maximize the total expected return of the portfolio, minimize the risk, and maximize the percent difference between estimated stock valuation and the current market valuation. For a Short-Only portfolio, we aim to minimize the total expected return of the portfolio, minimize the risk of the entire portfolio, and minimize the percent difference between estimated stock valuation and the current market valuation. This results in a trade-off problem in which weights will be chosen depending on a person's risk tolerance.

Full Model:

Model for Long Portfolio:

Model for Short-only Portfolio:

3. Solution

To expand on the possibilities for an optimal portfolio, we decided to construct both an optimal long position portfolio as well as an optimal short position portfolio. A fund manager may desire to allocate a portfolio to only short-positions to hedge themselves against their long positions and/or possible economic factors like a recession that might pull many of the stocks in the market lower. The traditional “buy-and-hold” investor may find that the long-only optimal portfolio is better suited for their needs. In addition, the short portfolio is neglecting some important as pects of borrowing shares including: borrowing rates, availability of shares to borrow, potential margin calls, etc. The potential loss on a short investment is theoretically unbounded, but we do not discuss these assumptions and technicalities in this report. An investor looking to short securities in practice would need to obtain a deeper understanding of the subject before attempting any endeavor.

The Equity Valuation Model is first constructed, since its results will be used in the Markowitz Optimal Portfolio models. It was desired by our group to obtain solutions that were “real”, so only real market data was used throughout the analysis. To build the Equity Valuation Model, we used 5 years worth of data (1,230 samples) to essentially train our LS Regression Model. By using the optimal weights for each fundamental characteristic, we are then able to estimate the value of a company by applying the weights to the fundamental data of any given company. Since the market capitalization is always known for each stock (market capitalization = # shares outstanding * share price), we can compare the estimated value from our model with the current market capitalization to determine if an equity is currently under/over or fair-valued. However, since the price of companies can vary widely, it was necessary that we looked at a relative measure of value difference instead of an absolute one. This meant looking at the percent difference of our expected price and the current price instead of simply taking the difference. Once we obtained a vector of calculated percent differences, we could then insert this information into the Markowitz Optimal Portfolio models.

When considering an optimal portfolio for long positions, we concerned our model with three different objectives: maximize expected returns, minimize risk, and maximizing the percent undervalued that a company is as determined by the previous model. It became necessary to model the objective function as a tradeoff between these three terms since all of them could not be solved to their absolute optimum simultaneously. Later in the report we will explore how different tradeoffs affect optimal portfolio composition as well as performance. Daily expected return data was collected for 306 equities and a covariance matrix of these equities was constructed. After having all pieces for the objective needed, we looked at reasonable constraints for the model. To ensure at least some diversification, we did not allow that more than 20% of the portfolio to be invested in any one stock. We also enforced that the entire portfolio be allocated completely. The long and short portfolios were constructed identically with the exception of desiring to maximize the percent overvalued that a stock is in the objective function.

To access the accuracy of our models, a test set of the 306 equities was gathered from the year 2014. A validation set was constructed with the same 306 equites for the year 2015. Optimal long and short portfolios were then constructed using the test set. Under the assumption that the portfolio was held for a year, we analyzed the results using the validation set.

# Helper function to calculate total profits and portfolio returns as a percent for each company
# selected by the model using what price the stocks were bought and sold at and the percent invested of the portfolio.
using DataFrames

function check_profits(ix, amount, prices_test, prices_val, xsol)
    profit = 0
    exp_returns = 0
    init_vals = prices_test[:,1] .* prices_test[:,2]
    final_vals = prices_val[:,1] .* prices_val[:,2]
    df = DataFrame()

    company_arr = []
    init_vals_arr = []
    final_vals_arr =[]
    invested_arr = []
    profit_arr = []

    for i in 1:length(ix)
        company = tickers[ix[i]]
        # Price - Valuation of company
        init_price = init_vals[ix[i]]
        final_price = final_vals[ix[i]]
        percent_invested = xsol[ix1[i]]
        #println("Percent invested: ", percent_invested)
        percent_invested = abs(percent_invested)
        invested = percent_invested*amount
        num_stocks = invested/init_price
        final_sell_price = num_stocks*final_price
        diff = final_sell_price - invested
        profit+=diff

        push!(company_arr, company)
        push!(init_vals_arr, init_price)
        push!(final_vals_arr, final_price)
        push!(invested_arr, percent_invested)
        push!(profit_arr, diff)

    end
    exp_returns = profit/amount

    df[:Companies] = company_arr
    df[:Valuation_when_bought] = init_vals_arr
    df[:Valuation_when_sold] = final_vals_arr
    df[:Percent_invested] = invested_arr
    df[:Returns] = profit_arr    
    println("Portfolio returns (percent) ", exp_returns)
    return df
end
check_profits (generic function with 1 method)
# Calculates the bias offset (difference) between the predicted valuation and actual valuation of a company while training the linear regression model.
function get_bias_diff(train, coeffs, test)
    actual_prices = train[78]
    num_shares = train[77]
    actual_valuations = actual_prices .* num_shares
    raw_temp = re_normalize(train)
    exp_valuations = raw_temp * coeffs
    bias = []
    for s in test[:,1]
        sum_diff_valuations = 0
        count = 0
        for i in 1:length(train[:,1])
            if train[i,1] == s
                sum_diff_valuations += exp_valuations[i] - actual_valuations[i]
                count += 1
            end
        end
        if count == 0
            avg = 0
        else
            avg = sum_diff_valuations/count
        end
        push!(bias, avg)
    end

    return bias
end
get_bias_diff (generic function with 1 method)
# Helper function to calculate difference between expected prices calculated by the model and actual prices as a percent
# for each company.
using LinearAlgebra

function get_diff_expected_prices(coeffs, raw_test, test_company_num)
    test_comp_name = raw_test[1][test_company_num]
    actual_prices = raw_test[78]
    num_shares = raw_test[77]
    actual_valuations = actual_prices .* num_shares
    raw_temp = re_normalize(raw_test) #normalize by scaling using the same scale factor    
    exp_valuations = raw_temp * coeffs #Calculate expected valuations by multiplying with our coefficients from the LS regression
    println("Calculated valuation for ", test_comp_name,  " before bias correction: ", exp_valuations[test_company_num])
    exp_valuations = exp_valuations - bias

    exp_prices = exp_valuations ./ num_shares
    diff = (exp_prices - actual_prices)./actual_prices
    println("Expected (calculated) valuation for ", test_comp_name,  " with bias correction: ", exp_valuations[test_company_num])
    println("Actual valuation for ", test_comp_name,  ": ", actual_valuations[test_company_num])
    println("Bias: ", bias[test_company_num])
    return diff
end
get_diff_expected_prices (generic function with 1 method)
# Helper function that takes in dataframe and returns columns 3 thru 76, normalized as a matrix.
using Statistics
# Scale is 75 because of an added term for intercept.
scale = ones(75)
function normalize(data)
    newdata = ones(length(data[:,1]), 75)

    for i in 3:76
        maxval = abs(maximum(data[:,i]))
        minval = abs(minimum(data[:,i]))

        #Normalizing the columns by dividing by maximum value so that all values are between -1 and 1
        if maxval != 0
            newdata[:,i-2] = data[:,i]/maxval
            scale[i-2] = maxval
        elseif minval != 0
            newdata[:,i-2] = data[:,i]/minval
            scale[i-2] = minval
            else #This branch will never really execute, but added it in just in case
            mean = mean(data[:,i])
            newdata[:,i-2] = data[:,i]/mean
            scale[i-2] = mean
        end
    end
    return newdata
end
normalize (generic function with 1 method)
# Helper Function to normalize test data by scaling with the same factor as train data.
function re_normalize(test)
    newdata = ones(length(test[:,1]), 75)

    for i in 3:76
        newdata[:, i-2] = test[:,i]
    end

    newdata = newdata ./ scale'
    return newdata
end
re_normalize (generic function with 1 method)
# CSV used to read in data from .csv files.
using CSV
file1 = "./fundementals_with_ratios_training_set.csv"
file2 = "./fundementals_with_ratios_testing_set.csv"
file3 = "./fundementals_with_ratios_validation_set.csv"
raw_train = CSV.read(file1);
raw_test = CSV.read(file2);
raw_val = CSV.read(file3);

# Merge the data into one dataframe. We will use this in our least squares model.
raw = vcat(raw_train, raw_test, raw_val)

1,230 rows × 78 columns

Ticker SymbolPeriod EndingAccounts PayableAccounts ReceivableAdd'l income/expense itemsAfter Tax ROECapital ExpendituresCapital SurplusCash RatioCash and Cash EquivalentsChanges in InventoriesCommon StocksCost of RevenueCurrent RatioDeferred Asset ChargesDeferred Liability ChargesDepreciationEarnings Before Interest and TaxEarnings Before TaxEffect of Exchange RateEquity Earnings/Loss Unconsolidated SubsidiaryFixed AssetsGoodwillGross MarginGross ProfitIncome TaxIntangible AssetsInterest ExpenseInventoryInvestmentsLiabilitiesLong-Term DebtLong-Term InvestmentsMinority InterestMisc. StocksNet BorrowingsNet Cash FlowNet Cash Flow-OperatingNet Cash Flows-FinancingNet Cash Flows-InvestingNet IncomeNet Income AdjustmentsNet Income Applicable to Common ShareholdersNet Income-Cont. OperationsNet ReceivablesNon-Recurring ItemsOperating IncomeOperating MarginOther AssetsOther Current AssetsOther Current LiabilitiesOther EquityOther Financing ActivitiesOther Investing ActivitiesOther LiabilitiesOther Operating ActivitiesOther Operating ItemsPre-Tax MarginPre-Tax ROEProfit MarginQuick RatioResearch and DevelopmentRetained EarningsSale and Purchase of StockSales, General and Admin.Short-Term Debt / Current Portion of Long-Term DebtShort-Term InvestmentsTotal AssetsTotal Current AssetsTotal Current LiabilitiesTotal EquityTotal LiabilitiesTotal Liabilities & EquityTotal RevenueTreasury StockEarnings Per ShareEstimated Shares OutstandingClose
String⍰Dates…⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Float64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Float64⍰Float64⍰Int64⍰Float64⍰Int64⍰Float64⍰Int64⍰Int64⍰Int64⍰Int64⍰Float64⍰Float64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Int64⍰Float64⍰Int64⍰Int64⍰Int64⍰Float64⍰Float64⍰Float64⍰Int64⍰Float64⍰Float64⍰Float64⍰Float64⍰Float64⍰Float64⍰Float64⍰Float64⍰
1AAL2012-12-313068000000-222000000-196100000023-1888000000469500000053133000000001270000001.0499e107802230000001001000000-1813000000-2445000000001.3402e100.0581.4356e10-5690000008.69e86320000005800000003060000004730000007.116e90.000-10200000001970000001285000000483000000-1571000000-18760000002050000000-1876000000-40840000001124000000386000000148000000121670000006260000004524000000-298000000015090000001100000015147000000-14100000084500000010318720-9.462e901297700000014190000003.412e92.351e107.072e99011000000-7.987e92.4891e101.6904e102.4855e10-3.67e8-5.63.35e813.5
2AAL2013-12-314975000000-93000000-272300000067-311400000010592000000752175000000050000001.1019e1010409350000001020000000-1324000000-2180000000001.9259e104.086e9591.5724e10-3460000002.311e98560000001012000000-1181000000-2350000001.5353e100.00022080000006600000006750000003799000000-3814000000-18340000001873000000-1834000000-4489000000156000000055900000013990000005229900000014650000007385000000-2032000000171100000048100000014915000000-560000008530000008807960-1.1296e1001291300000014460000008.111e94.2278e101.4323e1013806000000-2.731e94.5009e104.2278e102.6743e100.0-11.251.63022e825.25
3AAP2012-12-292409453000-8948200060000032-27118200052021500023598111000-26029800070003.10697e912400189544000657915000624074000001.29255e97.6389e7503.09804e92364040002.8845e733841000230860900004263230006.04461e80.000177445000540210000685281000127907000-2729780003876700002331100038767000038767000022986600006573150001131833000476140001495580002667000-33499000-179600023902100082130000105263407.149e8-1860000024407210006270000.04.61381e93.1842e925596380001.21069e93.40312e94.61381e96.205e9-2.7095e75.297.32836e771.51
4AAP2013-12-282609239000-32428000269800026-195757000531293000401112471000-20351300070003.24167e914400207795000663016000626398000001.28603e91.99835e8503.25215e92346400004.9872e736618000255655700001727150001.05267e90.000445679000514360000545250000331217000-362107000391758000-208800039175800039175800027759500006603180001039649000427610001546300003683000-27209000-166350000231116000110110000104165201.08911e9-7718400025918280009160000.05.56477e93.98938e927647850001.51621e94.04857e95.56477e96.49381e9-1.0789e85.367.30892e7109.92
5AAP2016-01-023757085000-21476000-748400019-234747000603332000290782000-24409600070005.31425e91300433925000269476000818296000752888000-421300001.43458e99.89484e8454.42277e92794900006.87125e865408000417476800001746670001.21316e90.000-426322000-13889000689642000-445952000-2533660004733980003025000047339800047339800059778800008257800008826330007740800039794000-44059000-13492000-186190002293540007423000083152002.02108e9-149100035969920005980000.08.13457e94.94075e937974770002.46065e95.67392e98.13457e99.73702e9-1.19709e86.457.3395e7150.51
6AAPL2013-09-2836223000000-1949000000115600000030-816500000009314259000000-973000000197640000001.07e111680262500000067570000005015500000050155000000001.6597e101.577e9386.4304e10131180000004.179e901764000000-2404200000083200000001.696e101.06e110016896000000351300000053666000000-16379000000-3377400000037037000000339400000037037000000370370000002409400000004899900000029514600000068820000007435000000-471000000-1082000000-1567000000202080000001080000000029412216444750000001.04e11-223300000001083000000002.6287e102.07e117.3286e10436580000001.24e118.3451e102.07e111.71e110.040.039.25231e8482.75
7AAPL2016-09-24593210000001044000000134800000036-1273400000008520484000000217000000312510000001.31e1113502930000000105050000006137200000061372000000002.701e105.414e9398.4263e10156850000003.206e902132000000-32022000000-18670000007.5427e101.7e110022057000000-63600000065824000000-20483000000-4597700000045687000000914800000045687000000456870000002929900000006002400000028875700000082830000008080000000634000000-1570000000-12210000003607400000010900000000284821133100450000009.6364e10-2922700000014194000000116050000004.6671e103.22e111.07e11790060000001.28e111.93e113.22e112.16e110.08.355.4715e9112.71
8ABBV2013-12-316448000000681000000-5400000092-49100000036710000001449595000000-56000000160000004.581e92590089700000056100000005332000000-1000000002.298e96.277e9761.4209e1012040000001.89e927800000011500000001775000000-4260000001.4292e101.18e800-60100000036940000006267000000-3442000000879000000412800000058400000041280000004128000000556900000033800000056640000003076700000012340000000-442000000-313000000-40500000035350000004590000000281192224328550000001.567e92700000053520000004310000003.0e82.9198e101.7848e1068790000004.492e92.4706e102.9198e101.879e10-3.2e82.581.6e952.81
9ABC2013-09-3014870635000-2312518000-4400019-202450000236099200081231006000-148657200026780008.54513e109700170793000898355000824458000008.03561e80.032.50782e93310230003.49971e9738970006981494000038308470001.39661e90.0000164398000788125000-7409870001172600004337070002354760004337070004934350006051920000089839900012217130001292310000-35483000-50538000319710000331652000-16974500016218600013605001.50841e9-328463000144723400000.01.89186e101.43937e10148706350002.31975e91.65989e101.89186e108.79592e10-1.51686e91.882.30695e861.1
10ABC2016-09-3024670159000-912724000504800067-4646160004333001000112741832000-110725200027780001.43e11900221477400039216600015308220001390910000001.53068e95.9915e934.27261e9-370190002.96785e9139912000107239200004071200030943400003.87024e90.0007132140005743900003178497000565072000-316917900014279290003301970001427929000142792900091758760000152577400013143250002102190000-1143080000-2745275000160470000-4615900036473500016514802.30394e916890300023820970006111490000.03.36562e102.28518e10252813080002.1294e93.15268e103.36562e101.47e11-4.39601e96.732.12174e880.78
11ABT2012-12-311088900000036000000-126000000022-1795000000011410802000000-417000000117550000008.899e9236321300000002782000000100000000-2200000004000000008.063e91.5774e10531.0151e10-4570000008.588e93200000003793000000-3062000000-14430000001.8085e102.74e8920000000441300000039890000009314000000195000000-556000000059630000002428000000596300000023700000010599000000013600000007017570000000-3594000000-521000000-7030000009057000000-35000000595000000113120714610000002.4151e10-514000000673500000023910000004.372e96.7235e103.1323e10132800000002.6721e104.0514e106.7235e101.905e10-5.591e93.761.5859e965.4999
12ABT2013-12-315948000000-1130000005300000010-11450000000853475000000-154000000120480000009.193e920221090000000171900000021860000002041000000-2600000005.971e99.772e9531.0464e10530000005.735e91450000002693000000-2225000000-11010000003.388e91.19e89600000001792000000-73270000003324000000-6696000000-39290000002576000000266000000257600000019880000006514000000021330000001101942000000386000000-2012000000-6396000000-55900000047910000001310000005880000001081317413710000002.1979e10-1210000000637200000031730000004.623e94.2953e101.9247e1095070000002.5171e101.7782e104.2953e101.9657e10-6.844e91.641.57073e938.33
13ADBE2013-11-29729257000336490009260004-18835800033926960002088345560000610005.86557e82650428902000321227000423649000356141000-524100006.59774e84.77198e9863.46868e9661560006.05254e8675080000-3091160001845020001.4993e92.07239e800-176000-5904960001151686000-559138000-1177803000289985000377832000289985000289985000702067000264970004227230001090121000170110000781715000461030000-680329000201817000-55509000522540009572658266310006.92896e9-5992240002140578000146760002.3392e91.03803e104.04593e915256480006.72463e93.65566e91.03803e104.05524e9-3.64319e90.584.99974e856.78
14ADI2013-11-02323084000123770008935000014-12307400071187900082139208900028527000518420009.41278e89594359000023401000110416000842425000815323000139400005.08171e82.84112e8641.69241e91418360002.8552e727102000283337000-9187200001291620008.72241e83.816e60040982000-136744000912345000-100557000-949926000673487000-5240800067348700067348700046144300029848000753075000294108400044733000247428000-80546000-845500091868000176020000107840002200003117269105130350004.0564e924574800039623300004.29082e96.38175e95.47243e95705120004.73958e91.64217e96.38175e92.63369e90.02.193.07528e849.68
15ADI2016-10-29431396000-93920001756600017-12739700040227000051892113200038221000513630001.19424e9635621570001360830002097900001045678000956921000-292900006.36116e81.67912e9652.22717e9952570005.49368e888757000376555000-9891830001015930001.73218e92.1937e700857175000367790001280895000-22917000-121827000086166400088952000861664000861664000477609000136840001028112000304672100064906000351538000-73814000-8787000-101690000153466000-9933000701230002819255876538160004.7858e9-30856500046143800003.13466e97.97028e94.97486e97829340005.16562e92.80466e97.97028e93.42141e90.00.968.97567e863.53
16ADM2013-12-31141350000002960000001550000007-9130000000487082000000254100000061360000008.5915e10182014480000009090000002437000000202400000004110000001.0137e100.043.889e96700000005.61e8413000000114410000001040000001910000005.347e94.046e9380000000-271300000014070000005226000000-3242000000-5770000001342000000300000001342000000175300000032240000002590000001871000000247800000063500000000-57000000730000002320000001105000000-950000000210110901.4077e10-101000000175900000015230000004.33e84.3752e102.853e10156580000002.0156e102.3558e104.3714e108.9804e100.02.036.61084e843.4
17ADS2012-12-31490095000-49219000080-116455000145423000028138604200009500002.39209e918130027000471092000274263000974364000682904000528000002.53028e81.75105e9341.2493e92606480005.82874e82914600000-1389770000907430004.70849e90.000233425300067713900011341900002209019000-267135000042225600043824200042225600042225600075750520000974364000272510140001710490002265359000-21861000-22000-11651250001259297000-42095000166876000191291218101.55326e9-10514400010805900022773230000.01.20001e109.13214e950327770005.28487e81.14717e101.20001e103.64139e9-2.45809e98.445.00303e7144.76
18ADS2013-12-31472326000-33414000058-135376000151275200033148017100009830002.89492e923024540004465050003072880001098912000793412000-1175800002.99188e81.7357e9331.42415e92972420004.60404e83055000000-145316300055200006.00271e90.000928674000764700001003492000704152000-1619416000496170000447854000496170000496170000868073000001098912000253456660002399410002650683000-18227000-22000-308770001426785000-21992600021611900018931123002.04943e9-21699500010911500013894890000.01.32443e101.04008e1045124980008.55761e81.23885e101.32443e104.31906e9-2.68918e910.094.91744e7262.93
19ADSK2013-01-31396700000-98100000012-5640000001871612200000014498000002.385e8245122800000187600000127800000310000000310000000200000001.149e88.715e8902.0737e9626000007.6e700-300000000850000007.456e84.111e800745600000455300000559100000541400000-647200000247400000194000000247400000247400000537300000439000003059000001315970000060800000647000000-5700000-6100000-2908000002883000003000000421000001315112456000000005.991e8-211000000108180000003.421e84.3084e92.5524e910437000002.0432e92.2652e94.3084e92.3122e90.01.092.26972e838.88
20ADSK2016-01-31522100000-195500000020-7240000001411353000000018215000003.707e818892000005180000001458000001300000-20300000-530000001.693e81.535e9852.1334e93102000007.08e7216000000-5441000003854000001.4877e95.323e800748300000-57600000414000000343200000-809500000-330500000408100000-330500000-330500000653600000013000000205600000886000001068900000-121100000-57900000-193000000299000000700000332000001113188790000000-8.08e7-347200000130890000008.979e85.5153e92.9931e915910000001.6196e93.8957e95.5153e92.5041e90.0-1.462.2637e846.82
21AEE2012-12-31671000000300000003300000015-106300000056160000007184000000-2800000020000003.477e9134038990000007360000001221000000829000000001.5348e104.11e8402.304e93070000001.4e7392000000570000000-19000000-560000005.802e94.08e81510000000-26000000-460000001690000000-426000000-1310000000-9740000002025000000-9740000005220000008860000000118800000021245300000019560000001568000000-8000000-12000000-2280000003076000000-4300000067300000014131711301.006e9-160000004430000004470000000.02.223e103.596e926860000006.616e91.5614e102.223e105.781e90.0-4.012.42893e830.72
22AEE2013-12-31947000000-60000000430000005-137900000056320000001300000006000000020000003.49e980038510000007610000001227000000829000000001.6205e104.11e8402.348e93110000000.0398000000526000000-17000000-1560000005.504e94.94e81420000000247000000-1790000001693000000-149000000-17230000002950000007030000002950000005180000001010000000011840000002019600000004060000006120000003000000-2000000-327000000254000000090000000706000000141355909.07e8-20000004580000009020000000.02.1042e101.972e924610000006.544e91.4498e102.1042e105.838e90.01.192.47899e836.16
23AEP2012-12-312185000000-160000001540000008-3025000000604900000010355000000-22400000032890000006.395e9671627000000104060000001918000000281000000018220000000440000003.8763e109.1e7578.55e96040000000.09880000001519000000-1800000001910000001.5586e102.074e900473000000580000003804000000-355000000-3391000000125900000067600000012590000001259000000187100000030000000026560000001872230000005200000001331000000-3370000005000000-1860000006315000000-30000001782000000121284506.236e983000000381200000033070000003.24e85.4367e104.589e968230000001.5237e103.913e105.4367e101.4945e100.02.64.84231e842.68
24AEP2013-12-312333000000229000001608000009-36164000006131000000918800000011920000033030000006.7223e9712038000000114440000001843100000298330000020933000000583000004.0997e109.1e7558.0912e96777000000.08900000001423000000-1122000001177000001.6828e102.229e910000000317000000-1612000004096200000-438700000-3817800000148420000049370000014805000001473900000186000000022640000028225000001967490000004860000001383000000-115000000115400000-16120000059440000001450000017125000001413104706.766e983200000332980000023960000003.53e85.6414e104.31e961120000001.6085e104.0329e105.6414e101.48135e100.03.044.88224e846.74
25AKAM2012-12-31176378000-210800071040009-1667730005195543000216201989000020150005.299e8359214270002565000204163000321591000321591000-8900003.45091e87.23701e8618.44047e81176020008.4554e700-222277000599460000.06.57659e8000-357208000530020000-108029000-7791100002039890006143800020398900020398900023919900040600031448700023398110005160400026566000-1640000-34690000-3900600004936400025920002096200023141535974744000-2.2257e9-9635400043344800002.35592e82.60063e97.28384e82029440002.34575e92.54873e82.60063e91.37395e9-6.24462e81.151.77382e840.91
26AKAM2013-12-31224095000-67184000558600011-1879640004561929000256333891000018080005.11087e839123250007936000184431000419554000419554000-365500004.50287e87.57368e8681.06684e91260670007.7429e700-19750000520800000.05.73026e8000131902000563908000-115243000-313108000293487000101602000293487000293487000293722000184300041396800026675360006209600039071000-2091000-41332000-10539400057152000-5080002154700027161939193879000-1.93222e9-9671200053559800003.40005e82.95769e91.02971e92631660002.62943e93.28254e82.95769e91.57792e90.01.651.77871e847.18
27ALB2012-12-31372309000-25992000122900017-280873000276100012447769600073640008890001.62031e936606336800099020000401012000368212000-2031000380670001.29657e92.76966e8368.98843e8804330009.4464e732800000428145000-26574000-94920006.86588e82.07141e8984100000-143900008280000488766000-177294000-301161000311536000904250003115360003258460004228170001116850003997830001615483600078655000085264000-91240006286000370318000-26860000152012254789190001.74468e9-42427000308456000127000000.03.43729e91.40731e93850090001.8336e91.60369e93.43729e92.51915e90.03.498.92653e762.12
28ALB2013-12-31411809000-65906000-667400025-1553460009957000109477239000-18100008010001.5438e9340012918800010737000057000100053844200012472000317290001.35707e92.84203e8368.50471e81344450008.8203e731559000436049000169000314520001.05431e92.12178e81154150000-18733000-457000432859000-288046000-157742000413171000-880160004131710004357260004919580003336100057667500024160229000776690000116245000-6149000-256500022216000099350000223317240822460001.50036e9-576745000158189000245540000.03.5848e91.48292e94363630001.62736e91.95744e93.5848e92.39427e90.04.938.38075e763.39
29ALK2012-12-3180600000090000002800000022-518000000660000000871740000000700000002.319e91160889000000264000000560000000514000000003.609e90.0502.338e91980000000.04600000058000000-82000000350000008.71e83.9e700-27500000020000000753000000-88000000-64500000031600000010000000316000000316000000278000000053200000011120000000123000000534000000-436000000216000000-450000008230000001190000002640000001136711201.127e9-2900000015420000001610000001.13e95.505e91.737e915010000001.421e94.084e95.505e94.657e90.04.477.06935e743.09
30ALK2013-12-31899000000-190000001300000025-5660000006060000008480000000010000002.355e911201044000000270000000851000000816000000003.893e90.0542.801e93080000000.03500000060000000-129000000880000007.54e80.000-161000000-42000000981000000-325000000-698000000508000000-160000000508000000508000000265000000083800000016183000000107000000564000000-18300000023000000-300000043100000029400000027000000016401010801.607e9-15900000016930000001170000001.25e95.838e91.762e915800000002.029e93.809e95.838e95.156e9-2.0e67.266.99725e773.37
using Statistics
# Normalize the data from the files into matrix B for the model
B = normalize(raw)

# Columns 77 and 78 are the estimated shares outstanding and closing price for each company.
prices = raw[:78]
shares = raw[:77]

# Calculate the market cap of each company.
mkt_cap = prices.*shares
y = mkt_cap;
# Equity Valuation Model

#Least Squares Linear Regression
# Can take ~5 mins to run. If you don't want to run the whole thing, please skip to the next cell.
using JuMP, Ipopt

m = Model(solver=IpoptSolver(print_level=0))
# Variable to hold weights of each fundamental attribute including intercept in column 75
@variable(m, u[1:75])
# Calculate least squares
# Objective to minimize the sum of squares between the companies' current market capitalization (y)
# and the market capitalization predicted by our model (B x u).
@objective(m, Min, sum( (y - B*u).^2 ) )

status = solve(m)
println(status)

# Coeffs is the variable to hold the weight ouputs of the model.
coeffs = getvalue(u)
println("Coefficient weights: ", coeffs)
Optimal
Coefficient weights: [-5.52662e14, 1.16507e10, -7.44934e10, -1.62888e11, 7.7802e12, 7.46124e10, 4.09376e9, 2.17528e11, 2.28959e10, 1.28349e10, 4.64297e12, -9.43487e9, 1.78499e11, -2.5365e11, 2.11437e11, 2.27914e13, -2.26833e13, 6.21952e9, -5.27838e10, 2.11628e12, 7.85458e11, 1.08062e10, 1.91159e12, 3.06959e10, 1.00392e12, -1.47748e12, -1.01068e10, 7.78183e12, 1.63795e11, -2.4329e11, 1.35878e12, -1.48416e11, -6.67235e9, 1.78606e11, -5.54145e11, 3.71803e11, 1.18462e11, -1.38982e12, -1.39441e12, 1.15752e11, 1.74413e12, -4.87292e10, -1.17391e10, 3.88778e10, 2.3876e11, -7.28409e10, 1.90456e11, -1.80126e10, -3.04466e14, -1.10013e9, 1.23101e10, 2.21372e12, -1.92899e11, 2.93459e10, -4.95802e10, 1.15052e11, 1.69296e11, 5.18205e10, 4.04073e9, -3.99459e10, 2.23452e11, 1.75842e10, 3.95502e10, -3.9155e14, 2.73132e11, -2.97284e12, 9.83579e11, 7.49975e14, -1.77718e12, -2.27975e12, 3.97454e12, -6.28953e12, -3.56524e10, -4.62922e9, -1.15785e9]
#If you don't want to run the previous optimization problem, here's the results from when we ran it.
#Please uncomment if you want to use this

#coeffs = [-5.5266e14, 1.16507e10, -7.44934e10, -1.62888e11, 7.7802e12, 7.46124e10, 4.09376e9, 2.17528e11, 2.28959e10, 1.28349e10, 4.64297e12, -9.43487e9, 1.78499e11, -2.5365e11, 2.11437e11, 2.27914e13, -2.26833e13, 6.21953e9, -5.27838e10, 2.11628e12, 7.85458e11, 1.08062e10, 1.91159e12, 3.06959e10, 1.00392e12, -1.47748e12, -1.01067e10, 7.78183e12, 1.63795e11, -2.4329e11, 1.35878e12, -1.48416e11, -6.67235e9, 1.78606e11, -5.54145e11, 3.71803e11, 1.18463e11, -1.38982e12, -1.39441e12, 1.15752e11, 1.74413e12, -4.87292e10, -1.17389e10, 3.88778e10, 2.3876e11, -7.28409e10, 1.90456e11, -1.80126e10, -3.04465e14, -1.10013e9, 1.23101e10, 2.21372e12, -1.92899e11, 2.93459e10, -4.95802e10, 1.15052e11, 1.69296e11, 5.18205e10, 4.04073e9, -3.99459e10, 2.23452e11, 1.75842e10, 3.95502e10, -3.91548e14, 2.73132e11, -2.97284e12, 9.83579e11, 7.49972e14, -1.77718e12, -2.27975e12, 3.97454e12, -6.28953e12, -3.56524e10, -4.62922e9, -1.15785e9];
bias = get_bias_diff(raw_train, coeffs, raw_test);
# Get the difference between expected prices calculated using the weights produced by the Equity Valuation Model and
# actual prices from the data set as a percent for each company.
percent_diffs = get_diff_expected_prices(coeffs, raw_test, 202)
println()
percent_diffs = get_diff_expected_prices(coeffs, raw_test, 2)
;
Calculated valuation for NFLX before bias correction: 2.8286596487435513e9
Expected (calculated) valuation for NFLX with bias correction: 2.296722593876831e10
Actual valuation for NFLX: 2.0527299215543518e10
Bias: -2.0138566290024757e10

Calculated valuation for AAPL before bias correction: 5.561365050864819e11
Expected (calculated) valuation for AAPL with bias correction: 5.3287233404792444e11
Actual valuation for AAPL: 6.1334861327025e11
Bias: 2.3264171038557495e10

Because of the lack of data, if a company’s value is artificially inflated or deflated by public opinion, such as Netflix’s stock, then the model will consistently underestimate or overestimate the stock’s value. Having more data to train the model with would help this issue, but a quicker solution would be to also find a market bias offset value when training the model that accounts for the difference between the models prediction and the actual market capitalization of the company. We are assuming that our model accurately predicts the fundamental value of the company, but we account for the market hype/pessimism by adding/subtracting to the value determined by our model. For example, the equity valuation model predicts Netflix (NFLX) value as $ 2.8 billion, but the actual market valuation is $ 20.5 billion. To account for this perceived potential and hype for Netflix we assign it a bias of nearly $ 20 billion. We also assume that a company’s bias (optimism, pessimism, or neutral) does not change throughout the years in our dataset. This only applies in the short run (since we’re using data that’s within a span of 4 years). But, in the long run, the company’s valuation should accurately be reflected by its fundamental data and shouldn’t need this correction. Another example for a company that is more established and stable can be seen by looking at Apple (AAPL). Our model predicts that Apple’s value is $ 556 billion when the actual market capitalization was $ 532 billion. Therefore, Apple’s bias was much less (in terms of percent) compared to Netflix. This reduced hype can be a result of investors believing that Apple won’t grow or shrink exponentially.

using CSV, LinearAlgebra
# Vector to hold the expected return of each company as a percent.
μ = convert(Vector, CSV.read("./expected-return-risk.csv", header = true)[2])
# Matrix to hold the expected varianve of each company as a percent squared.
Σ = convert(Matrix, CSV.read("./covariance-matrix.csv", header=false))
# Vector to hold the ticker symbol of each company.
tickers = convert(Vector, CSV.read("./expected-return-risk.csv", header = true)[1])  # Tickers

# Get the order of indices which will sort the assets by expected return.
ix = sortperm(μ)
# Variable to hold the number of assets.
nAssets = 306;
# Markowitz Modern Portfolio Model
# # This model finds the optimal long portfolio for one particular choice of λ

using JuMP, Mosek, PyPlot
function opt_long_portfolio(t1, t2)
    m = Model(solver = MosekSolver(LOG=0))
    # Variable to hold investment amounts.
    @variable(m, x[1:nAssets])
    # Investment amounts must be non-negative (cannot sell short assets).
    @constraint(m, max_c[i in 1:nAssets], x[i] >= 0)
    @constraint(m, min_c[i in 1:nAssets], x[i] <= 0.2)
    # You must invest all of the portfolio.
    @constraint(m,sum(x) == 1)

    figure(figsize=(12,8))

    subplot(211)
    # Variable for tradeoff weight for covariance matrix (risk).
    λ1 = t1
    # Variable for percent under/over valued determined by the Equity Valuation Model.
    λ2 = t2

    @objective(m, Min, -dot(μ,x) + λ1*dot(x,Σ*x) - λ2*dot(percent_diffs,x))

    solve(m)
    xsol1 = getvalue(x)

    exp_increase = dot(percent_diffs,xsol1)

    ix1 = findall(xsol1 .> 1e-4 )
    ret = dot(μ,xsol1)
    std = sqrt(dot(xsol1,Σ*xsol1))
    xlim(0,nAssets)
    bar(1:nAssets,xsol1[ix])
    title(string("Optimal long asset selection for λ1=",λ1,"  λ2=",λ2," ( \$\\mu=\$", round(ret,digits=3), "%, \$\\sigma=\$", round(std,digits=2), "% )"));
    tight_layout()
    return (xsol1, ix1, ret, std, exp_increase)
end
opt_long_portfolio (generic function with 1 method)
# Markowitz Modern Portfolio Model
# # This model finds the optimal short portfolio for one particular choice of λ

using JuMP, Mosek, PyPlot
function opt_short_portfolio(t1, t2)
    m = Model(solver = MosekSolver(LOG=0))
    # Variable to hold investment amounts.
    @variable(m, x[1:nAssets])
    # Investment amounts must be negative (selling short assets).
    @constraint(m, max_c[i in 1:nAssets], x[i] <= 0)
    @constraint(m, min_c[i in 1:nAssets], x[i] >= -0.2)
    # You must invest all of the portfolio.
    @constraint(m,sum(x) == -1)

    figure(figsize=(12,8))

    subplot(211)
    # Variable for tradeoff weight for covariance matrix (risk).
    λ1 = t1
    # Variable for percent under/over valued determined by the Equity Valuation Model.
    λ2 = t2

    @objective(m, Min, -dot(μ,x) + λ1*dot(x,Σ*x) - λ2*dot(percent_diffs,x))

    solve(m)
    xsol1 = getvalue(x)

    ix1 = findall(xsol1 .< -1e-4 ) #for short portfolio
    ret = dot(μ,xsol1)
    std = sqrt(dot(xsol1,Σ*xsol1))
    xlim(0,nAssets)
    bar(1:nAssets,xsol1[ix])
    title(string("Optimal short asset selection for λ1=",λ1,"  λ2=",λ2," ( \$\\mu=\$", round(ret,digits=3), "%, \$\\sigma=\$", round(std,digits=2), "% )"));
    tight_layout()
    return (xsol1, ix1, ret, std, exp_increase)
end
opt_short_portfolio (generic function with 1 method)

4. Results and Discussion

4.A. Standard Deviations and Expected Returns of Basket of Equities

using PyPlot
fig = figure(figsize=(12,6))

plot1 = fig[:add_subplot](2,2,1);
xlim(0,nAssets)
plot(μ[ix], linewidth = 1, c = :green)
plot([0,nAssets],[0,0],"k--")
ylabel("Expected return (%)")
title("Expected Daily Return of all Equities")

plot2 = fig[:add_subplot](2,2,2);
xlim(0,nAssets)
plot(sqrt.(diag(Σ))[ix],c = :blue)
ylabel("Standard deviation (%)")
title("Standard Deviation of all Equities")
tight_layout()

fig = figure(figsize=(16,4))
plot3 = fig[:add_subplot](1,2,1);
# plot correlation matrix (shows which assets are correlated with which other assets)
corr = diagm(0 => diag(Σ).^(-1/2))*Σ*diagm(0 => diag(Σ).^(-1/2))
imshow(corr[ix,ix]);colorbar();axis("image")
title("Correlation Matrix of all Equities")

# plot each asset individually
plot4 = fig[:add_subplot](1,2,2);
plot(sqrt.(diag(Σ)), μ, "r.")
xlabel("std deviation (%)")
ylabel("expected return (%)")
title("Expected Daily Return vs. Standard Deviation of all Equities")
tight_layout()
;

png

png

The four plots above show the following:

1. Expected Daily Return of all Equities (Top-Left):

This plot shows the expected daily return (%) of all equities that could make up the optimal portfolio. The equities are in sorted order from low to high expected returns which is why the curve is increasing from left to right. The range of expected returns for these 306 equites is from -0.04% to 0.27% per day. It is also noticed that there are very few equities that have a negative expected return. This will greatly reduce the available options to fill the short-only optimal portfolio if we weight the expected return term of the objective relatively more than the other terms.

2. Standard Deviation of all Equities (Top-Right):

This plot shows the daily standard deviation (%) of all equities. The trend of the plot is increasing overall. Since the stocks are sorted in increasing order in terms of their expected returns, it can be hypothesised that stocks with higher variability may also offer higher returns. The range of standard deviations for these 306 equities is from 0.81% to 4.00% per day.

3. Correlation Matrix of all Equities (Bottom-Left):

This plot shows the correlation between each pair of equities. The closer the color is to yellow, the more closely correlated the two stocks are; conversely, the closer the color is to purple, the more independent the two stocks are of each other. With a great number of comparisons, it becomes difficult to extract precise conclusions between any specific pair of stocks. Overall, it appears many of the stocks are fairly correlated (0.4-0.6).

4. Expected Daily Return vs. Standard Deviation of all Equities (Bottom-Right):

This plot reinforces the observation made from plot 2 that it appears that higher returns are associated with higher levels of variation. This can be extrapolated from the weak-moderate positive linear trend.

4.B. Optimal Portfolio Examples - Long Positions

# Optimal Long-only portfolio generated by just using the Markowitz MPT

λ1 = 0.1 #Risk tradeoff
λ2 = 0 #Tradeoff weight on valuation model

(xsol1, ix1, ret, std, exp_increase) = opt_long_portfolio(λ1, λ2)

# For later use in the pareto frontier
xsolm = xsol1
ixm = ix1

check_profits(ix1, 100000, raw_test[77:78], raw_val[77:78], xsol1)

png

Portfolio returns (percent) 22.555112327358362

22 rows × 5 columns

CompaniesValuation_when_boughtValuation_when_soldPercent_investedReturns
AnyAnyAnyAnyAny
1AAL3.84482e102.82953e100.0119159-314.659
2AAPL6.13349e116.60003e110.0443217337.131
3ABC1.73754e102.11682e100.0038370183.7569
4ALXN3.66159e104.03941e100.0374325386.25
5AWK9.55335e91.06921e100.0389212463.941
6AZO1.79235e102.29268e100.25582.84
7BIIB8.02108e107.06517e100.0713871-850.751
8CHD1.066e101.11293e100.001824818.03466
9CMG2.12448e101.49162e100.0614689-1831.1
10DG1.82128e102.0412e100.0382425461.784
11DLTR1.10019e101.46402e100.03815881261.9
12DPS1.40365e101.78012e100.0150951404.862
13GILD1.43477e111.48128e110.0500226162.178
14KMB4.33204e104.63867e100.0147808104.62
15KR1.87153e103.41887e100.06890815697.14
16MCK4.04733e105.24131e100.0185608547.549
17MO9.75777e101.14262e110.1136281942.83
18NFLX2.05273e104.83713e100.04175225663.43
19ORLY2.0093e102.53207e100.04752421236.47
20REGN4.00914e105.59636e100.03439621361.75
21ROST1.44685e101.89724e100.0029920993.1391
22SHW2.54484e102.40404e100.0448216-247.991
# Optimal Long-only portfolio generated using the Markowitz MPT and results from Valuation Model

λ1 = 0.1 #Risk tradeoff
λ2 = 0.1 #Tradeoff weight on valuation model

(xsol1, ix1, ret, std, exp_increase) = opt_long_portfolio(λ1, λ2)
check_profits(ix1, 100000, raw_test[77:78], raw_val[77:78], xsol1)

png

Portfolio returns (percent) 23.09653610517507

9 rows × 5 columns

CompaniesValuation_when_boughtValuation_when_soldPercent_investedReturns
AnyAnyAnyAnyAny
1AZO1.79235e102.29268e100.0186759521.324
2DLTR1.10019e101.46402e100.26613.96
3DUK5.91375e104.96381e100.2-3212.66
4F2.35562e105.58525e100.099055313580.8
5GILD1.43477e111.48128e110.0441801143.236
6MA1.00206e111.10341e110.22022.89
7NFLX2.05273e104.83713e100.03269834435.33
8PPL2.39035e102.30462e100.2-717.294
9RRC8.89966e94.09412e90.00539016-291.052

The first portfolio above shows what an optimized portfolio using purely MPT approach would look like. When using a trade-off weight of 0.1 for the risk of the portfolio, you can see the composition of the optimal portfolio as well as the resulting profit that could have been realized if held for a year (2014 - 2015). The annual returns are calculated as 22.6%.

The second portfolio mirrors the first with the addition of a non-zero weight to the third term of the objective function: maximizing percent difference between expected and actual value of the company (in 2014). When considering the difference in what the company is valued at and what it's current price is, the optimal portfolio generated consisted of mostly different stocks and we were able to achieve a portfolio that returned 23.10%.

In this example, the enhanced returns were nearly negligible; however, we can change the trade-off weights for different results.

4.C. Optimal Portfolio Examples - Short Positions

Note: Negative "Portfolio Returns" for a short porfolio denote a profit (since stocks were sold at higher level than they were later covered). Positive returns denote a loss on investement. We are not including potential borrowing rates since the investor does not own stock when shorting assets and must borrow them.

# Optimal Short-only portfolio generated by just using the Markowitz MPT

λ1 = 0.1 #Risk tradeoff
λ2 = 0 #Tradeoff weight on valuation model

(xsol1, ix1, ret, std, exp_increase) = opt_short_portfolio(λ1, λ2)
check_profits(ix1, 100000, raw_test[77:78], raw_val[77:78], xsol1)

png

Portfolio returns (percent) 2.2990736119473786

15 rows × 5 columns

CompaniesValuation_when_boughtValuation_when_soldPercent_investedReturns
AnyAnyAnyAnyAny
1CAG1.33069e101.62548e100.0281898624.488
2CLX1.18332e101.35577e100.0443318646.04
3CPB1.39224e101.48599e100.0498849335.941
4DGX9.73508e91.02517e100.0735371390.229
5ETR1.60312e101.08226e100.068168-2214.81
6FTR6.82392e93.15628e90.0211217-1135.23
7MCD9.19187e101.11015e110.04921331022.4
8NEM9.41294e99.20419e90.0939865-208.438
9PCG2.51459e102.60954e100.0992156374.632
10PEP1.46656e111.47748e110.005886154.3824
11PPL2.39035e102.30462e100.105759-379.301
12SO4.55445e104.35687e100.127116-551.448
13SPLS8.58863e91.09607e100.05495351517.75
14T1.81838e111.93756e110.0568821372.824
15WMT2.44188e112.74266e110.1217471499.6
# Optimal Short-only portfolio generated using the Markowitz MPT and results from Valuation Model

λ1 = 0.1 #Risk tradeoff
λ2 = 1 #Tradeoff weight on valuation model

(xsol1, ix1, ret, std, exp_increase) = opt_short_portfolio(λ1, λ2)
check_profits(ix1, 100000, raw_test[77:78], raw_val[77:78], xsol1)

png

Portfolio returns (percent) 28.01032203318026

8 rows × 5 columns

CompaniesValuation_when_boughtValuation_when_soldPercent_investedReturns
AnyAnyAnyAnyAny
1BBY8.02774e91.22951e100.00091417348.5949
2CF2.19106e109.13622e90.115879-6756.0
3FCX1.02154e107.2764e90.2-5754.0
4FTR6.82392e93.15628e90.2-10749.4
5HOLX7.0238e91.12e100.03146161870.64
6OKE1.04263e105.16336e90.0516852-2608.93
7R4.89685e93.01217e90.2-7697.53
8SYMC1.37763e101.6281e100.23636.28

The first portfolio above shows what an optimized portfolio using purely MPT approach would look like. When using a trade-off weight of 0.1 for the risk of the portfolio, you can see the composition of the optimal portfolio as well as the resulting profit that could have been realized if you sold short and held all of these positions for a year (2014 - 2015). The annual returns are calculated as -2.3%. This is likely caused by the fact that there are only a few stocks in our dataset that have negative expected returns.

The second portfolio mirrors the first with the addition of a non-zero weight to the third term of the objective function: minimizing percent difference between expected and actual value of the company (in 2014). When considering the difference in what the company is valued at and what it's current price is, the optimal portfolio generated consisted of mostly different stocks and we were able to achieve a portfolio that returned 27.9%.

In this example, the enhanced returns were quite signifigant and the addition of the valuation model proved to be quite successful. Again, we can change the trade-off weights for different results.

4.D. Pareto Frontier

# compute optimal tradeoff curve (this may take a few minutes)
N = 50
ret = zeros(N)
std = zeros(N)
lambda_values = exp10.(range(-3,stop=4,length=N))

m = Model(solver = MosekSolver(LOG=0))

@variable(m, x[1:nAssets])
@constraint(m, max_c[i in 1:nAssets], x[i] >= 0)
@constraint(m,sum(x) == 1)

for (i,λ) in enumerate(lambda_values)
    @objective(m, Min, -dot(μ,x) + λ*dot(x,Σ*x) )
    solve(m)
    xsol = getvalue(x)
    ret[i] = dot(μ,xsol)
    std[i] = sqrt(dot(xsol,Σ*xsol))
end
# plot tradeoff curve
plot(std,ret,"b-")
plot(sqrt.(diag(Σ)), μ, "k.", markersize=12)
plot(sqrt.(diag(Σ))[ixm], μ[ixm], "r.", markersize=12)  # low-risk portfolio
xlabel("std deviation (%)")
ylabel("expected return (%)")
#axis([1.5,4.5,0,.4]);
tight_layout()

png

The above plot shows the expected returns of the basket of stocks versus their respective standard deviation (or risk). The blue curve shows the trade off of different weights between maximizing returns and minimizing risk. Ideally, we would prefer stocks that have a high expected return coupled with a low risk. Since stocks that generate larger returns on average tend to pose greater risk, the investor may choose a tradeoff based on their risk tolerance.

The points in red are the stocks chosen for an optimal Markowitz MPT portfolio with the trade off of 0.1 for risk (The first long portfolio we generated above).

4.E Accuracy of Models and Possible Improvements

As discussed near the outset of this report, our group desired to build a project that could give some clear reflection of reality. There were a few instances where we encountered events that could lead to possible flaws in the conclusions that were determined.

The first potential issue was that we needed a sufficient amount of data for the Equity Valuation Model (LS Regression) to solve to optimality. This had two effects on our model. First, with the limited amount of data that we had, it became necessary to use the entire dataset (1,230 samples) to determine the optimal weights of each fundamental attribute. Consequently, the test data that is used to build the optimal portfolios in sections 4.b and 4.c are samples that were also used to build the model. This use of the data for the training set and the test set can lead to overfitting and results that may not be able to be achieved in practice. A potential improvement is to collect more data and have the training and test set completely independent of each other. The second problem lies with how people evaluate popular stocks. Because of the lack of data, if a company’s value is artificially inflated or deflated by public opinion, such as Apple’s stock, then the model will consistently underestimate or overestimate the stock’s value. Having more data to train the model with would help this issue.

Another potential issue that we noticed was that the data that we collected to build the optimal portfolios was mostly comprised of stocks that had a positive expected return. When constructing the short-only portfolio, we were then forced to give the expected return portion of the objective value less weight so that the model was not forced to choose between less than 5 stocks to generate a portfolio. To improve this, additional stock data would need to be collected so that there were more equities with negative expected returns.

We would also like to note something about the robustness of our model. The years that our sample data was collected ranged between 2012 to 2016. These years lie within a bull-market that followed the 2007-2008 financial crisis; thus, our model may not be suitable for all market conditions.

5. Conclusion

This optimization project explores the task of attempting to accurately value a company’s stock, and then use that valuation in a Markowitz portfolio in attempts to generate portfolios that will have superior returns coupled with reasonable risk. Given that many investors have different appetites for potential risks and possible rewards, we have provided a trade off curve to explore the interaction between multiple objectives: maximizing expected returns, and minimizing risk. A tradeoff surface exists when including the maximizing the amount that a company is undervalued (Minimize all objectives for short portfolio) objective but we couldn't generate a plot with meaningful insight, so it was excluded from the discussion. The project uses real data so that the derived results may be more significant and applicable in practice. In the future, we would like to have access to more data and from multiple time periods to increase the robustness of the proposed models. It may be possible to explore the plausibility of using different models during different market conditions, but these are just a few of the possible extensions to this project.

This project shows how optimization can be applied to financial markets and business valuation. We realize that many large corporations likely use much more sophisticated models than the ones proposed in this report; however, we believe that these models are adequate at introducing the lay-investor to optimization in finance and also do a fine job at accomplishing the objectives that we had laid out.

Disclaimer: The models and discussion in this report is not to be taken as investment advice. Use of this model in practice may lead to substantial losses in which our group is not responsible for. The models only exist for theoretical exploration and all conjecture is purely academic. Hypothetical or simulated performance is not indicative of any future results.

6. References

Chen, James. “Modern Portfolio Theory (MPT).” Investopedia, Investopedia, 17 Apr. 2019, www.investopedia.com/terms/m/modernportfoliotheory.asp.

Kenton, Will. “Markowitz Efficient Set.” Investopedia, Investopedia, 12 Mar. 2019, www.investopedia.com/terms/m/markowitzefficientset.asp.

McClure, Ben. “What Are Stock Fundamentals?” Investopedia, Investopedia, 2 Apr. 2019, www.investopedia.com/articles/fundamental/03/022603.asp.

Surz, Ron. “U.S. Stock Market Is Biggest & Most Expensive In World, But U.S. Economy Is Not The Most Productive.” NASDAQ.com, Nasdaq, 2 Apr. 2018, www.nasdaq.com/article/us-stock-market-is-biggest-most-expensive-in-world-but-us-economy-is-not-the-most-productive-cm942558.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •