68 views

Uploaded by ta9

Automatisation de la théorie de MArkowitz à travers Excel et VBA et d'autres méthode d'automatisation fichier en anglais

- Excel UnitOp
- VBA MsgBox Excel Examples - 100+ Message Box Macros
- Tutorial Vba Excel
- Writing Scripts
- March 2013
- Writing Scripts
- Design a VBA User Form - ComboBox and Open File Dialogue Box Controls
- Chapter 16
- MCA's XBRL Journey
- 2
- Tips
- Microsoft Visual Basic for Applications.pdf
- COM Collections
- Create Your Own Office Shortcuts
- Resume Planning
- DevelopigXBRLTaxonomiesInTheSpanishPublicSector
- White Paper: Streamlining Microsoft Office 2010 Migrations Using OfficeConverter
- Entrepreneurial Test
- liza
- IDXSummaryDocument_3

You are on page 1of 21

David Porter and Robert Stretcher

In the interest of reducing grading workload and managing cross-student sharing (cheating), we provide an example of

automating the construction of Markowitz (1959) efficient frontiers. The program automates the entire procedure from

downloading data for a specified number of securities (using either randomly generated securities from a provided list or

specified tickers) to generating graphs of the efficient frontier. Many commercially available optimization programs are

available, but this program is free to use and works within Microsoft Excel (2007-2010), the software package most

professors use when creating optimization assignments. The program is written in Visual Basic for Applications (VBA) but

does not require any knowledge of VBA to use. The program allows easy creation of random portfolios for student

assignments so that cross-student sharing can be minimized without adding an additional grading burden on the professor or

TA. The professor can also be assured that the stocks selected produce the desired type of optimization (actually work) before

using each set of securities. Where students are allowed to select their own portfolios, the program allows professors to

easily check computations and optimizations without having to manually optimize each portfolio. The program can also be

used to demonstrate the similarity of efficient frontiers across different stocks, portfolio sizes, and dates.

INTRODUCTION

Cutbacks in government funding to public universities

has resulted in reductions across many areas including but

certainly not limited to the hiring of new faculty to keep

class sizes small. As class sizes increase, grading of

assignments becomes more problematic both in the amount

of time required and in the possibility of cross-student

sharing (also referred to as free-riding or cheating). In the

case of investments courses, many professors require

students to complete some type of optimization assignment.

With class sizes exceeding 100 students, however, offering

individual students the opportunity to select their own

stocks makes the grading process difficult or prohibitive. As

a result, students are commonly placed in groups, and entire

classes may be assigned the same set of stocks to optimize.

Although this technique significantly reduces the length of

time needed to evaluate the assignments, it also increases

the probability of cross-student or cross-group sharing

making it difficult to determine which students actually

understand the optimization process. One solution to these

issues is to use an automated system designed to generate

Markowitz (1959) optimizations so that every group or

student could be either assigned a separate set of stocks to

optimize, or be allowed to select their own securities. In this

paper we describe a VBA program that can be used to

automate the optimization of portfolios using Solver in

Microsoft Excel. The object is not to teach VBA but to offer

some typical code that can be used to expedite a professors

use of this type of automation.

DESCRIPTION OF THE "FRONT-END" OF THE

PROGRAM

The program is designed for a personal computer (PC)

running a recent version of Excel (2007 or 2010) with the

of VBA, unless the individual professor wishes to adjust the

code for his/her own purposes. The program will not run on

an Apple operating system but could work if the MAC was

dual booted into Windows and was running the appropriate

Excel version. Since the VBA code is essentially a large

macro, when the file containing the program is opened, two

warnings may occur: (1) This file originated from an

Internet location and might be unsafe and, (2) Some active

content has been disabled. Click for more details. In both

cases, clicking Enable Content allows the VBA to run.

The file will then default to the "Explanation" sheet that

contains a brief explanation of the program.

As noted in the red box, the program downloads

monthly data from Yahoo for either a randomly selected

portfolio of securities or a specific set of ticker symbols. If

the user wants random portfolios, the number of securities is

entered in cell F1. If the user wants a specific set of

securities, the tickers should be entered in column A,

starting with cell A1, and cell F1 should be set to 0. Cell F1

is checked first, so if it contains a number between 2 and 20,

a random portfolio will be generated even if there are

specific tickers in column A. The restriction of 2 to 20

tickers is usually sufficient for most assignments but can

easily be altered by changing the VBA code. The program

will compute and graph the Markowitz optimization

assuming no short selling. Stocks with less than 30 months

of data are not used since the mean return is used as the

expected return and 30 observations is typically assumed to

be a reasonable statistical sample. The user can also

change the minimum observation assumption by altering the

VBA code.

the status bar at the bottom of the spreadsheet:

Figure 2. Status Bar.

generating portfolios. This sheet can be populated by the

user but the original file contains about 500 stocks as

examples. The "Prices" sheet contains the adjusted closing

prices downloaded from Yahoo. Since the program uses

monthly prices, these prices are the last adjusted closing

price of each month.

The "Returns" sheet contains the returns computations

based on the downloaded prices. Where the number of

prices differs across the securities, the returns are truncated

to the shortest set of data. This is necessary for the

computation of correlations and covariances. If the number

of returns is less than 30 for any of the securities the sample

is considered too small and the program will terminate.

The Basic Stats sheet contains summary measures for

the stocks: means, standard deviations, minimum return,

maximum return, and range of returns, as well as the

correlation matrix.

Figure 4. Returns Sheet.

in time. If it appears that nothing is happening, the user

should check the status bar. Also note that the program

generates six additional spreadsheets. Prices, Returns,

BasicStats, Model, ChartData and Graph. The seventh

10

Figure 5. Basic Stats Sheet.

Figure 7. ChartData Sheet.

dialog box pops up:

Figure 8. Date Selection Dialogue Box.

The "Model" sheet contains the data needed for the

optimization: the weights for each stock for the last

optimization run, the expected returns (the means), the

variance-covariance matrix, the expected return, variance

and standard deviation for the optimized portfolio and the

target cell. The target cell changes as the program generates

the chart data from the minimum variance portfolio to the

maximum return portfolio.

Figure 6. Model Sheet.

output for each of the 16 runs from the minimum variance

portfolio to the maximum return the weights for each

security for each run, as well as the portfolio expected return

and standard deviation. The number of runs is arbitrary and

16 (15 Solver runs plus the maximum return portfolio) was

chosen as a number that would produce a nice looking graph

the majority of the time.

The "Graph" sheet contains a scatter plot of the chart data.

Since most graphs of the efficient frontier look better with

more points near the minimum variance point, the chart data

is generated using that assumption. The graph will also

auto-scale itself based on the data. An example of the graph

output is in Figure 10.

Use the mouse to select the desired start and end dates.

There are several checks built into the dialog box such as

the date cannot be in the future and the start date must be

before the end date. Once again, the user is reminded that a

minimum of 30 observations must be used. Once the dates

are selected and the OK is clicked, a number of observations

check dialog box is displayed:

Figure 9. Download Initiation Selection Box.

dialog box. After clicking Yes, the user can watch the

11

status bar as the program attempts to download the data

from Yahoo and complete the optimization. Once

completed, the "Graph" sheet is shown:

Figure 10. Markowitz Graph Output.

UW-Whitewater runs two sections of undergraduate

Investments each term with section sizes between 55 and 60

students. Lectures and exams cover the optimization process

for two risky assets when rf exists, but the undergraduate

students rarely show a thorough understanding of the

method. One way to increase their understanding is use real

world data with more than 2 risky assets. With

undergraduates, 5 risky assets is sufficient to determine if

they can complete the optimization process and graph an

efficient frontier. Instructions on how to download data

from finance.yahoo.com are provided to students along with

instructions on how to optimize a portfolio using Solver in

Excel. Some textbooks contain this information but the

undergraduate textbook currently in use at UW-Whitewater

does not. The yahoo instructions are also available from the

authors and instructions for Markowitz style optimization

are available in many textbooks including Bodie, Kane and

Marcus, Investments (McGraw-Hill Irwin), Chapter 7,

Appendix A (pages 234-239 in the 9th edition) and Craig

Holden's Excel Modeling and Estimation in Investments

(Pearson Prentice Hall), Chapters 7 and 8 in the 3rd edition.

When class sizes were smaller (in the early 1990's

Investment class sizes at Whitewater were in the 15-20

range), students were put into small groups and allowed to

select their own securities. Grading of 6-10 assignments was

not prohibitive and assignments could be returned in a few

days. As class sizes grew, group sizes increased but class

sizes reached the point where it was necessary to assign a

single group of specific stocks for the entire class. These

adjustments allowed the grading of 30-40 assignments in a

reasonable timeframe but dramatically increased the amount

of cross-group sharing. Requesting students behave ethically

and increasing the penalty for cross-group sharing had little

effect on the issue. It was clear that each group or student

would need to be assigned a separate set of securities and

that a more efficient method of grading had to be used; thus

the development of the automated program.

We use the program for several purposes. For the

undergraduates, we randomly generate the 5 stock portfolios

they use in their optimizations. If there are 40 groups, we

randomly generate 40 5-stock portfolios. Since the program

generates the graph for the random securities, it is possible

to determine if the optimization produces a "good" graph

before including that set of securities in the assignment.

Students may select different points for their optimization

than the automated program but the program significantly

reduces the time needed to determine if the optimization

was done correctly. For the graduates, they select their own

10 stock portfolios, but those assignments can still be easily

graded since the program can download and optimize a 10

stock portfolio in about 5 seconds (assuming a reasonable

Internet connection). We also use the program in-class to

demonstrate to students that most efficient frontiers have a

similar shape regardless of the time period, length of time

period or number of securities in the portfolio. We find that

simply discussing correlations and their relationship to the

shape of the efficient frontier is never as effective as using

real data. The students also get to see the entire process

from hand calculating a two stock optimization, to using

Excel to optimize a multi-stock portfolio, to a fully

automated computation of an optimization.

Assigning every group their own set of stocks has

significantly reduced the amount of cross-group sharing but

free-riding within groups still exists. Use of student selfevaluations within the group helps with this issue but often

students are more concerned they will have to work with the

same student again in another class than they are with the

ethics of giving another student a good evaluation when

they were actually a free-rider.

CONCLUSION

This paper described the "front-end" of an automated

program for generating efficient frontiers using Microsoft

Excel. The program can be used to reduce grading time

while significantly curtailing cross-group sharing (cheating)

when professors use assignments to improve student

understanding of Markowitz (1959) optimizations. The

program is freely available by contacting David Porter in the

UW-Whitewater Department of Finance and Business Law.

To minimize the distribution of the program to students,

professors should use either their office phone or university

email as evidence they are not a student. For those familiar

with VBA, a PDF file is also available which explains the

code thereby reducing the learning curve if changes are

desirable to meet the individual needs of a specific course.

To view the VBA code in the Excel file, use Alt+F11 or use

12

Excel toolbar by default but can be turned on by going to

File | Options | Customize Ribbon and checking

Developer under the Main Tabs. The code can then be

viewed by clicking on "View Code":

Demonstrating Retrieval of

Financial Information in

XBRL

(Jade) Fang

Module "MainApplication":

Figure 12. Main Application Location.

upgraded the existing system of Electronic Data Gathering,

Analysis, and Retrieval (EDGAR), to Interactive Data

Electronic Applications (IDEA) platform, using eXtensible

Business Reporting Language (XBRL). In January 2009, the

SEC issued its final mandate for XBRL adoption and the

conversion target dates for all firms. This conversion

enables users to retrieve listed companies financial

statement information at two levels, document and the data

element, compared to the document level alone under the

existing system of EDGAR. Beneficial to all users, this

change is particularly important to resource-strapped

entities such as small businesses, and universities. The

result is user friendly for students researching information.

With simply the industry standard tool of Microsoft Excel,

without expensive proprietary XBRL modules, detailed

information is now available, quickly, efficiently and at

minimum cost. This paper explains the basic concept of

XBRL and demonstrates the ease of the retrieval process in

Microsoft Excel.

INTRODUCTION

REFERENCE

Markowitz, H. (1959). Portfolio Selection: Efficient

Diversification of Investments, John Wiley & Sons, New

York City, New York.

David Porter is a Professor of Finance at the University of

Wisconsin-Whitewater.

Robert Stretcher is a Professor of Finance at Sam Houston

State University.

Commission (SEC) chairperson, Mary Schapiro, announced

the agencys final mandate for eXtensible Business

Reporting Language (XBRL) adoption and the firm

conversion target dates (SEC, January 2009). The mandate

stated the largest domestic and foreign public companies

that use U.S. Generally Accepted Accounting Principles

(GAAP) to file their financial statements in XBRL format

by June 15, 20091: medium-sized filers by June 15, 2010,

and the rest of the filers, either using U.S. GAAP or

International Financial Reporting Standards (IFRS), by June

15, 2011 (Fang 2010).

The new rules are intended to make financial

information easier for investors to analyze and to assist in

automating regulatory filings and business information

processing. The XBRL system lists information at both the

document level, such as the entire set of financial statements

for a given firm, and the data element level, such as

individual accounts like inventory. In XBRL interactive

data, or data tagged at the data element level, can function

across multiple and/or different platforms or application

programs. Thus, XBRL has the potential to increase the

speed, accuracy and usability of financial disclosure, and

13

This file describes the functions and subroutines used to gather the data and generate the optimization

for the application titled "Automating Markowitz Optimizations using VBA". We use one form to request

the start and end dates for the data that is not described below. The object is not to teach VBA

programming but to provide some guidance to expedite the learning curve for those wishing to alter the

code for their own needs. We would describe the code below as "typical" code that can be found online or

in a good VBA book such as Power Programming with VBA by John Walkenback or VBA and Macros for

Microsoft Excel by Bill MrExcel Jelen and Tracy Syrstad.

The code begins with Option Explicit requiring that all variables be explicitly declared. Option Base 1

starts the array counters at 1 instead of the default 0. Most of the variables are declared as Public so they

are usable in all subroutines:

Option Explicit

Option Base 1

Public nTickers As Long, nSymbols As Long, nRandom As Long

Public nSamples As Long, i As Long, j As Long, k As Long, MinObs As Long

Public Symbols() As String, Symb As String, LegalName() As String

Public IndexSymbol As String, IndexName As String, maxTicker As String

Public LendRate As Single, BorrowRate As Single, RiskAversion As Single

Public EndMonth As Integer, EndDay As Integer, EndYear As Integer

Public StartMonth As Integer, StartDay As Integer, StartYear As Integer

Public nMonths As Integer, nRuns As Integer

Public EndDate As Date, StartDate As Date

Public Msg As String, Ans As Variant

Public maxStdDev As Double, maxReturn As Double, MVPStdDev As Double

Public MinVar As Boolean, Frontier As Boolean, AllowShort As Boolean

Public Error As Boolean

Public FormatRange As Range

The main application starts with additional variable declarations and then sets the display alerts and

screen updating to false (turns them off). Since the program updates the status bar, it is turned on:

Sub MainApplication()

Dim Msg As String, Ans As String

Dim ColNum As Long, nRow As Long

Dim UsedRow() As Integer

Dim SheetName As Worksheet

Dim Duplicate As Boolean

On Error Resume Next

Application.DisplayAlerts = False

Application.ScreenUpdating = False

Application.DisplayStatusBar = True

Although it is personal preference, we prefer to start everything from a blank slate so we delete previous

worksheets:

If SheetExists("Prices") Then Sheets("Prices").Delete

Sheets.Add after:=Sheets("Stocks")

ActiveSheet.Name = "Prices"

Sheets.Add after:=Sheets("Prices")

ActiveSheet.Name = "Returns"

If SheetExists("BasicStats") Then Sheets("BasicStats").Delete

Sheets.Add after:=Sheets("Returns")

ActiveSheet.Name = "BasicStats"

If SheetExists("Model") Then Sheets("Model").Delete

Sheets.Add after:=Sheets("BasicStats")

ActiveSheet.Name = "Model"

If SheetExists("ChartData") Then Sheets("ChartData").Delete

Sheets.Add after:=Sheets("Model")

ActiveSheet.Name = "ChartData"

If SheetExists("Graph") Then Sheets("Graph").Delete

In this example, we either randomly generate the stocks to be used in the optimization by selecting them

from the worksheet Stocks or use the supplied symbols. First, check to see if the random value in cell

F1 is set to zero and if it is then count the number of tickers in column A, check that there are between 2

and 20 tickers, redimension the arrays for the number of tickers and read in the tickers:

nRandom = Range("F1").Value

If nRandom = 0 Then

nTickers = Cells(Rows.Count, 1).End(xlUp).Row

If nTickers < 2 Or nTickers > 20 Then

Msg = "You must have between 2 and 20 tickers. Either the " & vbCrLf & _

"random number of tickers must be between 2 and 20, " & vbCrLf & _

"or the number of tickers must meet the same criteria."

Ans = MsgBox(Msg, vbOKOnly + vbExclamation)

Exit Sub

End If

ReDim UsedRow(nTickers)

ReDim Symbols(nTickers)

For i = nTickers To 1 Step -1

Symbols(i) = Range("A1").Offset(i - 1, 0).Value

Next i

End If

If the random value in cell F1 is not zero, then check that the random value is between 2 and 20 and

redimension the arrays for the appropriate number:

If nRandom <> 0 Then

nTickers = nRandom

If nTickers < 2 Or nTickers > 20 Then

Msg = "You must have between 2 and 20 tickers. Either the " & vbCrLf & _

"random number of tickers must be between 2 and 20, " & vbCrLf & _

"or the number of tickers must meet the same criteria."

Ans = MsgBox(Msg, vbOKOnly + vbExclamation)

Exit Sub

End If

ReDim UsedRow(nTickers)

ReDim Symbols(nTickers)

Count the number of security symbols on the "Stocks" sheet and make sure it is greater than the random

number in cell F1:

Sheets("Stocks").Select

If nSymbols < nTickers Then

Msg = "The number of security symbols on the Stock sheet " & vbCrLf & _

"is less than the random number in Cell F1. Please add " & vbCrLf & _

"more security symbols or reduce the random number."

Ans = MsgBox(Msg, vbOKOnly + vbExclamation)

Exit Sub

End If

Initialize the random number generator and create an array of random numbers:

Randomize

For i = 1 To nTickers

Do

nRow = Int(Rnd() * nSymbols)

If nRow = 0 Then nRow = 1

Duplicates are not allowed, so check to see if the random ticker has been used before. If it has, generate

a new random number:

Duplicate = False

For j = 1 To i

If UsedRow(j) = nRow Then Duplicate = True

Next j

Loop While Duplicate

UsedRow(i) = nRow

Symbols(i) = Sheets("Stocks").Range("A1").Offset(nRow, 0).Value

Next i

End If

Stock tickers can be illegal names for named ranges, so set up a set of legal names:

ReDim LegalName(nTickers)

For i = 1 To nTickers

LegalName(i) = "Stock" & i

Next i

With Sheets("Explanation")

Range("AA1:AG65500").Clear

End With

Set the Error to False before calling the GetYahooData Subroutine (this routine accesses

finance.yahoo.com and downloads the data) and then check the Error after the subroutine to see if there

was an error accessing the data. If there was, exit the program:

Error = False

Call GetYahooData(ColNum)

If Error Then

Sheets("Explanation").Select

Range("F1").Select

Exit Sub

End If

Although it is personal preference, it might be useful to let the user know if there was an issue trying to

download a particular ticker:

If ColNum < nTickers Then

Msg = "Yahoo reports that the ticker '" & Symb & "' does not exist," & vbCrLf & _

"or does not exist for the specified dates." & vbCrLf & _

"This may be from an internet error or a ticker symbol error." & vbCrLf & _

"If you are sure that this ticker symbol is correct then you should" & vbCrLf & _

"close Excel then try running the program again."

Ans = MsgBox(Msg, vbOKOnly + vbExclamation)

Sheets("Explanation").Select

Exit Sub

End If

Call the Returns subroutine (to compute the returns). Again if there is an error, exit the program:

Call Returns

If Error Then Exit Sub

Create named ranges for the returns for each of the stocks:

For k = 1 To nTickers

Sheets("Returns").Range("A2").Offset(0, k - 1).Resize(MinObs).Name = LegalName(k)

Next k

Call each of the subroutines need to compute and chart the optimization:

Call GetStats

Call ModelSheet_Setup

Call ChartDataSheet_Setup

If Error Then Exit Sub

Call UpdateChart

The main program finishes by turning on the display alerts and screen updating, then clears the status

bar and ends the subroutine:

Application.DisplayAlerts = True

Application.ScreenUpdating = True

Application.StatusBar = Empty

End Sub

The main program calls the function SheetExists and returns TRUE if a worksheet exists in the active

workbook. As noted above, if the sheet exists, we delete it so we always start from a clean slate:

Public Function SheetExists(sname) As Boolean

Dim x As Object

On Error Resume Next

Set x = ActiveWorkbook.Sheets(sname)

If Err.Number = 0 Then SheetExists = True _

Else SheetExists = False

End Function

The web query to download data from Yahoo can be found in Bill Jelens book referenced above. We

place the web query in the subroutine GetYahooData. The subroutine begins with variable declarations

and then opens the form frmGetDates. This form requests the start and end dates for the data and does

a few checks such as making sure the end date is not before the begin date and the end date is not in the

future. You could just as easily put the dates in cells on the Explanation sheet but the form is a bit more

professional:

Sub GetYahooData(ColNum As Long)

Dim LastRow As Long

Dim FreqS As String

Show (display) the form GetDates to the user so that they can select the start and end dates for the data:

frmGetDates.Show

If Error Then Exit Sub

For simplicity, we only use monthly data in this example. We also need to adjust the information passed

from the form GetDates so it matches what is expected by Yahoo (January is month 0 and December

month 11):

FreqS = "m"

StartMonth = StartMonth - 1

EndMonth = EndMonth - 1

Then for each ticker, we request the selected data from Yahoo. The counter ColNum is set to zero for

starters:

ColNum = 0

For i = 1 To nTickers

Sheets("Explanation").Select

Range("AA1:AG65000").Clear

Symb = Symbols(i)

Application.StatusBar = "Attempting to Download " & Symb & " ..."

With ActiveSheet.QueryTables.Add(Connection:= _

"URL;http://ichart.finance.yahoo.com/table.csv?s=" & Symb & _

"&a=" & StartMonth & "&b=" & StartDay & "&c=" & StartYear & _

"&d=" & EndMonth & "&e=" & EndDay & "&f=" & EndYear & "&g=" & FreqS _

, Destination:=Range("AA1"))

.RefreshStyle = xlOverwriteCells

.RowNumbers = False

.FillAdjacentFormulas = False

.BackgroundQuery = True

.SavePassword = False

.SaveData = True

.AdjustColumnWidth = False

.RefreshPeriod = 0

.Refresh BackgroundQuery:=False

.WebSelectionType = xlSpecifiedTables

.WebTables = "19"

Most of the options, RefreshStyle, etc., are not needed for the query to work but are usually kept for

clarity. We have run the query with only the last three options. A complete list of options is available at the

Microsoft Developer Library: http://msdn.microsoft.com/enus/library/microsoft.office.interop.excel.querytable_properties.aspx. Note that the WebTables page of 19

requires either some good guessing or an examination of the source code at Yahoo. There is no direct

way to determine the correct web table to download so if Yahoo moves where the table is located, this

number will need to be changed.

The data is downloaded as comma delimited so it must be parsed into columns. There are many ways to

do this but the example below is relatively efficient:

Sheets("Explanation").Range("AA1").Select

Range(Selection, Selection.End(xlDown)).Select

Selection.TextToColumns Destination:=Range("AA1"), DataType:=xlDelimited, _

TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=True, Tab:=False, _

Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo:= _

Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1), _

Array(7, 1)), TrailingMinusNumbers:=True

End With

If the query was successful, increment the counter:

ColNum = ColNum + 1

Determine how much data was downloaded and copy the closing prices to the prices sheet:

LastRow = Sheets("Explanation").Cells(Rows.Count, 27).End(xlUp).Row

Sheets("Prices").Range("A1").Offset(0, ColNum) = Symbols(i)

Sheets("Explanation").Range("AG1:AG" & LastRow).Copy _

Sheets("Prices").Range("A2").Offset(0, ColNum)

Next i

After downloading the data for each of the tickers, copy the dates to the Prices sheet, set the column

width and set the correct date format:

Sheets("Explanation").Range("AA1:AA" & LastRow).Copy

Sheets("Prices").Range("A2").PasteSpecial (xlPasteValues)

Sheets("Prices").Columns("A:A").ColumnWidth = 12.86

Selection.QueryTable.Delete

Set the correct date format on worksheet "Prices":

With Sheets("Prices")

.Activate

Range("A1").Select

If FreqS = "m" Then .Range("A3:A" & LastRow).NumberFormat = "[$-409]mmm-yy;@"

Add some other formatting:

Range("B3").Resize(LastRow, nTickers).NumberFormat = "0.00"

With Range("A1").Resize(2, nTickers + 1)

.Interior.Color = 13209

.Font.ThemeColor = xlThemeColorDark1

.Font.Bold = True

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlCenter

End With

Range("A1").Interior.ColorIndex = xlNone

With Range("A2:A" & LastRow)

.Font.ThemeColor = xlThemeColorDark1

.Interior.Color = 13209

.Font.Bold = True

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlCenter

End With

End With

To complete the subroutine, clear the data range and turn off copy mode:

Sheets("Explanation").Range("AA1:AG65500").Clear

Application.CutCopyMode = False

End Sub

The Returns subroutine computes returns from the prices downloaded from Yahoo. It starts with an

additional variable declaration and sets the Symb variable to null (blank).

Sub Returns()

Dim LastRow As Long

Symb = ""

Determine the minimum number of observations for each ticker:

For i = 1 To nTickers

LastRow = Sheets("Prices").Cells(Rows.Count, i + 1).End(xlUp).Row - 2

If i = 1 Then

MinObs = LastRow

Else

If LastRow < MinObs Then

MinObs = LastRow

Symb = Symbols(i)

End If

End If

Next i

Returns have one less observation than prices:

MinObs = MinObs - 1

If a symbol has fewer observations than the others, report that symbol to the user:

If Not Symb = "" Then

Msg = "Minimum number of observations is " & MinObs & " for symbol " & Symb

Ans = MsgBox(Msg, vbOKOnly)

End If

If a symbol has fewer than 30 observations, report that to the user, set the Error to true, delete the

BasicStats worksheet and exit the subroutine:

If MinObs < 30 Then

Msg = "Minimum number of observations is less than 30" & Chr(10) & _

"Terminating the application."

Ans = MsgBox(Msg, vbOKOnly)

Error = True

If SheetExists("BasicStats") Then Sheets("BasicStats").Delete

Sheets("Explanation").Select

Exit Sub

End If

On the Returns sheet, insert the ticker symbols for the titles:

Sheets("Returns").Select

For i = 1 To nTickers

Range("A1").Offset(0, i - 1) = Symbols(i)

Next i

Compute the returns:

Range("A2") = "=(Prices!B3-Prices!B4)/Prices!B4*100"

Range("A2").AutoFill Destination:=Range("A2").Resize(, nTickers), Type:=xlFillDefault

Range("A2").Resize(, nTickers).AutoFill Destination:=Range("A2").Resize(MinObs, nTickers),

Type:=xlFillDefault

Add some formatting:

Range("A2").Resize(MinObs, nTickers).NumberFormat = "0.0000"

Set FormatRange = ActiveSheet.UsedRange.SpecialCells(xlCellTypeConstants, 2)

With FormatRange

.Interior.Color = 13209

.Font.ThemeColor = xlThemeColorDark1

.Font.Bold = True

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlCenter

End With

End Sub

The GetStats subroutine computes the basic statistics from the returns.

Sub GetStats()

The subroutine starts by selecting the BasicStats worksheet, then adds some formatting and the titles:

Sheets("BasicStats").Select

Range("A:A").ColumnWidth = 12

Range("A1:D1").MergeCells = True

Range("A1").Value = "Summary Measures for Stock Returns"

Range("A3").Value = "Stocks"

Range("A4").Value = "Means"

Range("A5").Value = "Std. Dev."

Range("A6").Value = "Min"

Range("A7").Value = "Max"

Range("A8").Value = "Range"

Range("A10").Value = "Correlations"

For each ticker, enter the formulas for the average, standard deviation, minimum, maximum and range of

returns:

For i = 1 To nTickers

Range("A3").Offset(0, i).Value = Symbols(i)

Range("A4").Offset(0, i).Formula = "=Average(" & LegalName(i) & ")"

Range("A5").Offset(0, i).Formula = "=Stdev(" & LegalName(i) & ")"

Range("A6").Offset(0, i).Formula = "=Min(" & LegalName(i) & ")"

Range("A7").Offset(0, i).Formula = "=Max(" & LegalName(i) & ")"

Range("A8").Offset(0, i).FormulaR1C1 = "=R[-1]C-R[-2]C"

Next

Insert the titles (symbols) for the correlation table:

With Range("A10")

For i = 1 To nTickers

With .Offset(i, 0)

.Value = Symbols(i)

End With

With .Offset(0, i)

.Value = Symbols(i)

End With

Next

Compute the correlations:

For i = 1 To nTickers

For j = 1 To nTickers

.Offset(i, j).Formula = "=Correl(" & LegalName(i) & "," & LegalName(j) & ")"

Next

Next

End With

Add some formatting:

Range("B4").Resize(nTickers + 7, nTickers).NumberFormat = "0.0000"

Set FormatRange = ActiveSheet.UsedRange.SpecialCells(xlCellTypeConstants, 2)

With FormatRange

.Interior.Color = 13209

.Font.ThemeColor = xlThemeColorDark1

.Font.Bold = True

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlCenter

End With

End Sub

The ModelSheet_Setup subroutine sets up the model worksheet with the necessary data to optimize the

portfolio and calls the subroutine "Solver" to perform the optimization:

Sub ModelSheet_Setup()

Dim modelSheet As Worksheet

Set modelSheet = Worksheets("Model")

Application.StatusBar = "Calculating Covariances"

With modelSheet

.Activate

Add some formatting and setup the titles:

.Columns("A:A").ColumnWidth = 12

.Columns("B:F").ColumnWidth = 9.29

.Range("A1:C1").MergeCells = True

.Range("A1").Value = "Portfolio Selection Model"

With .Range("A3")

.Value = "Stock"

.Offset(1, 0).Value = "Weights"

.Offset(2, 0).Value = "Means"

For i = 1 To nTickers

.Offset(0, i).Value = Symbols(i)

Enter the naive weights as a starting point for the optimizations:

.Offset(1, i).Value = 1 / nTickers

Enter the average returns as the expected returns:

.Offset(2, i).Formula = "=Average(" & LegalName(i) & ")"

Next

End With

Create named ranges for the weights and expected returns:

With .Range("A4")

Range(.Offset(0, 1), .Offset(0, 1).End(xlToRight)).Name = "Weights"

Range(.Offset(1, 1), .Offset(1, 1).End(xlToRight)).Name = "Means"

End With

Sum the weights, add a title, and create a named range:

With .Range("A3").Offset(0, nTickers + 1)

.Value = "Sum"

.Offset(1, 0).Name = "SumWeights"

.Offset(1, 0).Formula = "=Sum(Weights)"

End With

Add the titles for the covariance table:

With .Range("A7")

.Value = "Covariances"

For k = 1 To nTickers

.Offset(k, 0).Value = Symbols(k)

.Offset(0, k).Value = Symbols(k)

Next k

Compute the covariances:

For i = 1 To nTickers

For j = 1 To nTickers

.Offset(i, j).Formula = "=Covar(" & LegalName(i) & "," & LegalName(j) & ")"

Next

Next

Range(.Offset(1, 1), .Offset(nTickers, nTickers)).Name = "Covar"

End With

With .Range("A7").Offset(nTickers + 2, 0)

Add the title for the expected return on the portfolio and enter the formula to compute its value:

.Value = "E(Rp)"

.Offset(0, 1).Name = "ERp"

.Offset(0, 1).Formula = "=Sumproduct(Weights,Means)"

10

Add the title for the target cell and set its starting value to zero. The target cell is used as the target for the

optimization

.Offset(0, 3).Value = "Target"

.Offset(0, 4).Value = 0

.Offset(0, 4).Name = "Target"

Add the title for the variance of the portfolio and enter the formula to compute its value:

.Offset(2, 0).Value = "Var(Rp)"

With .Offset(2, 1)

.FormulaArray = "=MMult(Weights,MMult(Covar,Transpose(Weights)))"

.Name = "VarRp"

End With

Add the title for the standard deviation of the portfolio and enter the formula to compute its value:

.Offset(2, 3).Value = "Sigma(Rp)"

With .Offset(2, 4)

.Formula = "=Sqrt(VarRp)"

.Name = "SigmaP"

End With

End With

End With

Add some formatting and end the subroutine:

Range("B4").Resize(nTickers + 8, nTickers + 1).NumberFormat = "0.0000"

Set FormatRange = ActiveSheet.UsedRange.SpecialCells(xlCellTypeConstants, 2)

With FormatRange

.Interior.Color = 13209

.Font.ThemeColor = xlThemeColorDark1

.Font.Bold = True

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlCenter

End With

End Sub

The subroutine ChartDataSheet is used to call RunSolver and record the solutions for each optimization

on the ChartData sheet for charting. It starts with some additional variable declarations:

Sub ChartDataSheet_Setup()

Dim CDSheet As Worksheet

Dim nErr As Integer

Dim MVPRet As Double, Temp1 As Double, Temp2 As Double

Dim SameReturn As Boolean

Dim T1 As Double, T2 As Double, T3 As Double

Set CDSheet = Worksheets("ChartData")

Add some formatting and titles:

With CDSheet

.Select

.Cells.ClearContents

11

.Range("A:Z").Font.Bold = False

.Columns("A:A").ColumnWidth = 15.14

.Columns("B:B").ColumnWidth = 12.14

.Columns("C:C").ColumnWidth = 10.86

.Range("A1").Value = "Efficient Frontier"

.Range("B2").Value = "Port. Std.Dev."

.Range("C2").Value = "Port. Return"

.Range("E1").Value = "Optimal Portfolio Weights"

.Range(Cells(1, 5), Cells(1, nTickers + 4)).MergeCells = True

With .Range("D2")

For k = 1 To nTickers

.Offset(0, k).Value = Symbols(k)

Next

End With

End With

Find the highest return and the matching standard deviation - the endpoint of the efficient frontier:

With Sheets("BasicStats")

.Activate

For i = 1 To nTickers

If i = 1 Then

maxReturn = Range("A4").Offset(0, i).Value

maxStdDev = Range("A5").Offset(0, i).Value

maxTicker = Range("A3").Offset(0, i).Value

Else

If maxReturn < Range("A4").Offset(0, i).Value Then

maxReturn = Range("A4").Offset(0, i).Value

maxStdDev = Range("A5").Offset(0, i).Value

maxTicker = Range("A3").Offset(0, i).Value

End If

End If

Next i

End With

Number of times to run Solver to get a "nice" graph:

nRuns = 15

Compute the minimum variance portfolio:

Range("Target") = 0

Call RunSolver

Copy the expected return, standard deviation and weights to the appropriate cells:

With CDSheet.Range("A" & nRuns + 3)

.Value = "M-V Portfolio"

.Offset(0, 1).Value = Range("SigmaP").Value

.Offset(0, 2).Value = Range("ERp").Value

.Offset(0, 2).Name = "MVPReturn"

For k = 4 To nTickers + 3

.Offset(0, k).Value = Range("Weights").Cells(k - 3).Value

Next

End With

MVPRet = Range("MVPReturn").Value

12

MVPStdDev = Range("SigmaP").Value

Use an exponential function to select more points near the minimum variance point. The divisor "T1"

should scale between 0 and 1. The 1.5 is arbitrary and is used to get the graph to look appropriate:

T1 = 1 / Exp(1 / 1.5)

Run Solver "nRuns" times and record the results. Solver can make errors, so set the error counter to zero

and increment with each error:

For i = nRuns - 1 To 1 Step -1

nErr = 0

Set the target cell for each optimization by altering the standard deviation between the minimum variance

point and the maximum standard deviation:

T2 = 1 / Exp((i + 1) / 1.5)

T3 = T2 / T1

Range("Target") = MVPStdDev + T3 * (maxStdDev - MVPStdDev)

Run Solver with the new target cell. Since Solver can make errors, check for an error after each run and

re-run if necessary:

Do

Call RunSolver

With CDSheet.Range("B4")

.Offset(i - 1, 0).Value = Range("SigmaP").Value

.Offset(i - 1, 1).Value = Range("ERp").Value

End With

Make sure Solver did not get stuck and return an inferior point:

SameReturn = False

Temp1 = Round(CDSheet.Range("C4").Offset(i - 1, 0).Value, 4)

Temp2 = Round(CDSheet.Range("C4").Offset(i, 0).Value, 4)

If Temp1 <= Temp2 Then

SameReturn = True

Sheets("Model").Range("B4").Resize(, nTickers).Value = 0

nErr = nErr + 1

If nErr = 1 Then Sheets("Model").Range("B4") = 1

If nErr = 2 Then Sheets("Model").Range("C4") = 1

If nErr = 3 Then Sheets("Model").Range("D4") = 1

If nErr = 4 Then Sheets("Model").Range("E4") = 1

If nErr = 5 Then Sheets("Model").Range("F4") = 1

If nErr = 6 Then Sheets("Model").Range("B4").Resize(, nTickers).Value = 1/nTickers/2

If nErr = 7 Then Sheets("Model").Range("B4").Resize(, nTickers).Value = 1/nTickers*2

If nErr > 7 Then

Error = True

MsgBox "Error in Solver Solution"

Exit Sub

End If

End If

If the point is an inferior point, run Solver again with the same target cell:

Loop While Same Return

13

Write the optimal weights for each stock for each for each run:

With CDSheet.Range("D4")

For k = 1 To nTickers

.Offset(i - 1, k).Value = Range("Weights").Cells(k).Value

Next

End With

Next i

The maximum return is the last point on the efficient frontier:

CDSheet.Range("B3").Value = maxStdDev

CDSheet.Range("C3").Value = maxReturn

With CDSheet.Range("D2")

For k = 1 To nTickers

If .Offset(0, k).Value = maxTicker Then

.Offset(1, k).Value = 1

Else

.Offset(1, k).Value = 0

End If

Next

End With

Add some formatting and end the subroutine:

CDSheet.Activate

With Range("A1").Resize(nRuns + 3, nTickers + 4)

.NumberFormat = "0.0000"

.HorizontalAlignment = xlCenter

.VerticalAlignment = xlCenter

End With

Set FormatRange = ActiveSheet.UsedRange.SpecialCells(xlCellTypeConstants, 2)

With FormatRange

.Interior.Color = 13209

.Font.ThemeColor = xlThemeColorDark1

.Font.Bold = True

End With

End Sub

The subroutine RunSolver runs the Solver optimization routine:

Sub RunSolver()

Sheets("Model").Select

We include the code to run Solver directly but there can be conflicts if Solver is not correctly installed and

referenced. Application.Run does not have as many conflict issues as just using Solver but it runs slower

and is not as intuitive since the options are not referenced with words. For a good description of this issue

see http://peltiertech.com/Excel/SolverVBA.html. We start by resetting Solver:

SolverReset

The first constraint is that the weights must sum to 1. "Relation:=2" refers to "=":

SolverAdd CellRef:=Range("SumWeights"), _

14

Relation:=2, _

FormulaText:=1

The second constraint is that the portfolio standard deviation must equal the target cell:

SolverAdd CellRef:=Range("SigmaP"), _

Relation:=2, _

FormulaText:=Range("Target")

The maximization function will vary depending on the computation. In this example, we maximize the

portfolio expected return by changing the weights. A "MaxMinVal=1" refers to maximizing:

SolverOk SetCell:=Range("ERp"), _

MaxMinVal:=1, _

ByChange:=Range("Weights")

In this example we run Solver with all the options set to the default, (there is no Solver options line). Since

the Solver option AssumeNonNeg is set to True by default, it is not necessary to add the constraint that

the weights are >= 0 when short selling is not allowed. A complete list of options along with their default

values is available at the Microsoft Developer Library, http://msdn.microsoft.com/enus/library/office/ff195446.aspx. You can also find references to the other Solver functions on the same

page.

Run the optimization. "UserFinish:=True" completes the optimization without asking if the user want to

keep the optimization:

SolverSolve UserFinish:=True

Reset the status bar to empty and end the subroutine:

Application.StatusBar = Empty

End Sub

The UpdateChart subroutine plots the chart data. It also starts with the declaration of a few variables

specific to this subroutine:

Sub UpdateChart()

Dim minX As Single, maxX As Single

Dim minY As Single, maxY As Single

Dim xLength As Single, yLength As Single

Application.StatusBar = "Updating Chart"

Activate the chart data sheet, select the chart type, data range, location, style, labels format, axis

captions:

Sheets("ChartData").Activate

ActiveSheet.Shapes.AddChart.Select

ActiveChart.ChartType = xlXYScatterSmooth

ActiveChart.SetSourceData Source:=Range("ChartData!$B$3:$C$" & nRuns + 3)

ActiveChart.Location Where:=xlLocationAsNewSheet

ActiveChart.ChartStyle = 36

ActiveChart.ClearToMatchStyle

ActiveChart.SetElement msoElementLegendNone

15

ActiveChart.Location Where:=xlLocationAsNewSheet

ActiveChart.Axes(xlValue).TickLabels.NumberFormat = "0.00"

ActiveChart.Axes(xlCategory).TickLabels.NumberFormat = "0.00"

ActiveChart.SetElement (msoElementPrimaryCategoryAxisTitleAdjacentToAxis)

ActiveChart.Axes(xlCategory, xlPrimary).AxisTitle.Caption = _

"Standard Deviation of Portfolio Returns %"

ActiveChart.SetElement (msoElementPrimaryValueAxisTitleRotated)

ActiveChart.Axes(xlValue, xlPrimary).AxisTitle.Caption = "E(Rp) %"

ActiveChart.Name = "Graph"

Sheets("ChartData").Move Before:=Sheets("Graph")

Update the chart settings to improve chart spacing and end the subroutine:

minX = Application.WorksheetFunction.Min(Range("B3:B" & 18))

maxX = Application.WorksheetFunction.Max(Range("B3:B" & 18))

minY = Application.WorksheetFunction.Min(Range("C3:C" & 18))

maxY = Application.WorksheetFunction.Max(Range("C3:C" & 18))

xLength = maxX - minX

yLength = maxY - minY

Sheets("Graph").Select

With ActiveChart

With .Axes(xlCategory)

.MinimumScale = minX - 0.1 * xLength

.MaximumScale = maxX + 0.1 * xLength

End With

With .Axes(xlValue)

.MinimumScale = minY - 0.1 * yLength

.MaximumScale = maxY + 0.1 * yLength

End With

End With

Application.StatusBar = Empty

End Sub

16

- Excel UnitOpUploaded byChava Tututi
- VBA MsgBox Excel Examples - 100+ Message Box MacrosUploaded byradhika1992
- Tutorial Vba ExcelUploaded byAgungRiyadi
- Writing ScriptsUploaded byfede444
- March 2013Uploaded byrag
- Writing ScriptsUploaded bychris75726
- Design a VBA User Form - ComboBox and Open File Dialogue Box ControlsUploaded byReaper's Scythe
- Chapter 16Uploaded byIvan Bliminse
- MCA's XBRL JourneyUploaded byIRIS Business Services Limited
- 2Uploaded bymudassir2640
- TipsUploaded byVijayaLakshmi Iyer
- Microsoft Visual Basic for Applications.pdfUploaded byJoão Baptista
- Create Your Own Office ShortcutsUploaded byRoberto Zanetto
- COM CollectionsUploaded bySaravanan Kasinathan
- Resume PlanningUploaded byVijendra Singh Jhala
- DevelopigXBRLTaxonomiesInTheSpanishPublicSectorUploaded byBakhtiar Alakadarnya
- White Paper: Streamlining Microsoft Office 2010 Migrations Using OfficeConverterUploaded byJoanneThomsonCT
- Entrepreneurial TestUploaded byunderwood@eject.co.za
- lizaUploaded byEmha
- IDXSummaryDocument_3Uploaded byTomy Rizky Izzalqurny
- SpiderDiagramBSp_WithInstructionsUploaded byKR
- Payroll Discoverer Cheat SheetUploaded byChary Madarapu
- RS Logix + ComparisonUploaded bySoumojit Mukhopadhyay
- hoe_ch01Uploaded byWesley Florvil
- ExcelUploaded byDionel Rizo
- Accounting Assistant or Administrative AssistantUploaded byapi-78023025
- GAAP - TUploaded byShilpa Alagh
- Ax2012 Enus Deviv 06 01 Lab CodeUploaded byaimi99
- white page engl317 hmUploaded byapi-301525475
- 24PT633R-37_L01.1UAC (según mismo chassis de 21pt6331_85r)Uploaded byRodolfo Gtz

- j200 Quarterly-dailydata-eur Stocksweight 20140930Uploaded byta9
- The Prediction Error of the Chain LadderUploaded byta9
- lex_assurances_20100416.pdfUploaded byta9
- Friedland_estimating.pdfUploaded byta9
- WatchlistUploaded byta9
- Net Premium CalculationsUploaded byta9
- Commutation SymbolsUploaded byJhon Carlo Mangubat
- Programme Coupe Du Monde Bresil 2014Uploaded byLaurentZONGO

- IS295a -ASDean (OGIS)Uploaded byDean Alan
- notes scatter plotsUploaded byapi-256105506
- mobiscope_getstartUploaded bylolopera
- A Current-Mode Control TechniqueUploaded byGanesh Dharmireddy
- SoftwareQualityUploaded byMarthony Mandra
- Epm InstallUploaded byMushtaq Ahmed
- GoProStudio2.5 User Manual WindowsUploaded bymiguel suarez
- Sextic Anharmonic Oscillators and Orthogonal PolynomialsUploaded byBruna Israel
- Microsoft Corporation v. Geotag. No. 2015 1140 Fed. Cir. Apr. 1 2016Uploaded byAlan Engle
- Ingenico Telium ConfigurationUploaded byUmesh Kumawat
- G120_EntrenamientoUploaded byRicky Mclaughlin
- TM tablrt conter.pdfUploaded byHeryanto Matheos
- 0478_y16_sp_1Uploaded byTich
- Sol13 (Solutions to Chapter 13)Uploaded byluda392
- Editing Media with AV Foundation.pdfUploaded byjase21
- 78 Microsoft Interview Questions _ Impact InterviewUploaded byramakanthd92
- DRDO Previous Interview Questions PaperUploaded byDibyanshu Kumar
- Easy GuiUploaded byAndriantsalama
- Ac - De Re de Dicto DistinctionsUploaded byKK-bookslover
- HowTo Netgear Business 1.0.2Uploaded byHeilel Heilela
- Directorate of Primary EducationUploaded bykhalidhassan566
- mergingLO-ac.docUploaded byAldo Ramirez
- x220_datasheetUploaded bydanieltettley
- thrun.3D-EMUploaded byjimakosjp
- EspindolaPizanoArielTonatiuh_Lab1Uploaded byArielTonatiuh
- Chapter 3 PROBABILITYUploaded bysplashsplish
- b.sc Syllabus(Semester Wise) 2015Uploaded byWaaiz Mohammed
- ASSIGNMENT OF SIGNALS AND SYSTEMUploaded byNitish Kumar Yadav
- Serial Communication ProtocolsUploaded byVissu Sweet
- Home Language Survey Data Quality Self-AssessmentUploaded bycorey_c_mitchell