SOME EXCEL STUFF
Our process starts by giving the client the ability to create any peer group(s) of investments around any mutual funds, ETFs, closed-end, private portfolios and custom portfolios.
We create custom benchmarks according to our client’s (and their investors) world-view.
We maintain a terabyte-size proprietary 1940-act fund operations and performance database to research a wide array of subjects, from r-square performance attribution to effective advisory fees.
Past research includes:
- Administration fee comparisons
- Advisory metrics
- Performance fee models
- Legal costs
- Sales and redemption analysis
- Portfolio Commissions
- Start-up funds
- 3-factor tracking
- New funds data
Here’s some sample VBA I wrote to enhance an Excel chart. The following chart is not built-in to Excel; that is, I had to develop, or program, a custom routine to add the quartile / quintile boxes on the right.

VBA code…
Sub ab00_CHART_RelativePerfRanking_ALL_RUN_nTile()
Dim iDataRowStart As Integer
Dim iDataRowEnd As Integer
Dim sDataSeries As String
Dim dFunds As New Dictionary
Dim xFunds As Variant
Dim sChartCaption As String
Dim sDataSheet As String
' ***** CONFIG ********************
sDataSheet = "DATA_PerformanceRankings"
' Fill working fund dictionary list
Dictionary_Fill_gdRA_MasterListColVals 2 ' 1 would be ticker
' Quartile (4) or Quintile (5), or other?
nTile = 5
' *********************************
' ***
' Create 1-Year Charts (cols E,F,G)
' ***
For Each vKey In gdRA_MasterListColVals.Keys
' GET FUND ... RA_MasterList data
vxcols = Split(gdRA_MasterListColVals.Item(vKey), "|")
sFund = vxcols(1) ' would be short name we use for sheet name
PeerGroup = vxcols(0) ' 1st col, PeerGroup
' Find where the fund's data block begins (row number)
iDataRowStart = SheetRowGetNum(sDataSheet, "A1", PeerGroup)
If iDataRowStart > 0 Then
vCheckHasData = Sheets("DATA_PerformanceRankings").Range("E" & iDataRowStart).Value + _
Sheets("DATA_PerformanceRankings").Range("F" & iDataRowStart).Value + _
Sheets("DATA_PerformanceRankings").Range("G" & iDataRowStart).Value + _
Sheets("DATA_PerformanceRankings").Range("H" & iDataRowStart).Value
If vCheckHasData > 0 Then
sDescription = Sheets("DATA_PerformanceRankings").Range("D" & iDataRowStart).Value
If InStr(sDescription, "Lipper") > 0 Then
sChartCaption = "* Rankings relative to selected peer group; smaller percentages indicating better relative performance"
Else
sChartCaption = "* Rankings relative to selected peer group; smaller percentages indicating better relative performance"
End If
' Now create chart Sheet, RangeStart, ChartName, Left, Top, sDataSeries
' POSITION: TOP/LEFT
' 5.25, 123, (4.6 * 72), (2.75 * 72),
ab00_CHART_RelativePerfRankings_Draw_nTile sDataSheet, _
"A", _
iDataRowStart, _
sFund, "I7", "RelPerfRank", 339, 80.25, _
sDataSeries, "2015 Relative Performance Ranking* (% and quintile)", _
sChartCaption, nTile
Else
currSheet = ActiveSheet.Name ' get current sheet name to go back to
' go to chart sheet
Sheets(sFund).Select
CHARTS_DrawBox_PerfRankingsMissing
Sheets(currSheet).Select ' now back to where we were
End If
End If 'exist
Next
Range("a3").Select
End Sub
Sub ab00_CHART_RelativePerfRankings_Draw_nTile(argDataSheet, argDataCol, argDataRow, _
argSheet, argCellPositionFirst, argChartName, argL, argT, sSeriesData, argTitle, argChartCaption, argnTile)
' ****** GET CHART DATA **************
Dim sR1 As String
' Add bank for reference
Dim sDataSheet As String
sDataSheet = "=" & argDataSheet & "!"
' We'll need 3 rows, so make strings for them
sR1 = Trim(Str(argDataRow)) ' First Row, was +3 for original type
' And we'll need 3 series (name/value pairs)
Dim s1N, s1V, sXlegend As String
' Legend same for all
sXlegend = sDataSheet & "$E$1:$G$1"
' Legend same for all
sXlegend = sDataSheet & "$E$1:$G$1"
'"Data_1_3_5_10_Year").Range("E5:H5"
s1N = sDataSheet & "$E" & sR1 & ":G" & sR1
s1V = sDataSheet & "$E$" & "1" & ":$G$" & "1" ' prob won't use this
' Let's pass these pack as one pipe-deliminated string
sSeriesData = s1N & "|" & s1V & "|" & sXlegend
' ******* END GET CHART DATA *************
Sheets(argSheet).Select
Range(argCellPositionFirst).Select
' DELETE
NumCharts = ActiveSheet.ChartObjects.Count
For ic = NumCharts To 1 Step -1
If ActiveSheet.ChartObjects(ic).Name = argChartName Then
ActiveSheet.ChartObjects(ic).Delete
End If
Next ic
'
Dim xSeriesData
xSeriesData = Split(sSeriesData, "|")
' Now go to range where we want to create chart (though we'll really use Left/Top coordinates)
Range(argCellPositionFirst).Select
ActiveSheet.Shapes.AddChart.Select
ActiveChart.Parent.Name = argChartName ' Name Chart
ActiveChart.ChartType = xlColumnClustered
ActiveChart.ClearToMatchStyle
ActiveChart.ChartStyle = 3
ActiveChart.ClearToMatchStyle
' Get Data
ActiveChart.SeriesCollection.NewSeries
ActiveChart.SeriesCollection(1).Name = xSeriesData(1) '"=Data_1_3_5_10_Year!$D$2" ' Series 1 Name
ActiveChart.SeriesCollection(1).Values = xSeriesData(0) '"=Data_1_3_5_10_Year!$F$2:$F$2" ' Series 1 Values
'ActiveChart.SetSourceData Source:=Sheets("Data_1_3_5_10_Year.Range("E5:H5")") '"(Data_1_3_5_10_Year").Range("E5:H5)"
ActiveChart.SeriesCollection(1).xValues = xSeriesData(2) '"=Data_1_3_5_10_Year!$E$1:$H$1"
' Change Scale 1 to 0 in .25s
ActiveChart.Axes(xlValue).Select
ActiveChart.Axes(xlValue).MinimumScale = 0
ActiveChart.Axes(xlValue).MaximumScale = 1
' Either Quartile or Quintile For now
If argnTile = 4 Then
ActiveChart.Axes(xlValue).MajorUnit = 0.25 ' QUARTILES
Else
ActiveChart.Axes(xlValue).MajorUnit = 0.2 ' QUINTILES
End If
ActiveChart.Axes(xlValue).TickLabels.NumberFormat = "0%"
' Reverse, from top down
ActiveChart.Axes(xlValue).ReversePlotOrder = True
Selection.MajorTickMark = xlNone
' Change Column Widths
ActiveChart.SeriesCollection(1).Select
ActiveChart.ChartGroups(1).Overlap = 100
ActiveChart.ChartGroups(1).GapWidth = 35
' Change colors
With Selection.Format.Fill
' RBB Method works
' .Visible = msoTrue
' .ForeColor.RGB = RGB(0, 128, 128)
' .Transparency = 0.4392156601
' .Solid
.ForeColor.ObjectThemeColor = msoThemeColorAccent5
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = -0.25
.Transparency = 0.4392200112
End With
' Add Chart Titles
' Can't RESIZE CHART TIEL WIDTH SO DO BOX INSTEAD
ActiveChart.SetElement (msoElementChartTitleCenteredOverlay)
Selection.Caption = "" 'argTitle ' like "One Year Performance"
'ActiveChart.ChartTitle.Select
'Selection.Format.TextFrame2.TextRange.Font.Size = 12
' TITLE BOX
ActiveChart.Shapes.AddTextbox(msoTextOrientationHorizontal, _
17, _
0.3, _
315, _
22).Name = "TBTitle"
ActiveChart.Shapes("TBTitle").Select
Selection.Height = 22
Selection.ShapeRange.TextFrame2.TextRange.Font.Size = 11
Selection.ShapeRange("TBTitle").TextFrame2.TextRange.Characters.Text = argTitle '"2013 Relative Performance Ranking (% and quartile)*"
ActiveChart.Shapes.Range(Array("TBTitle")).Select
Selection.ShapeRange.TextFrame2.TextRange.Font.Bold = msoTrue
Selection.ShapeRange.TextFrame2.TextRange.ParagraphFormat.Alignment = _
msoAlignCenter
Selection.ShapeRange.TextFrame2.TextRange.Font.Fill.ForeColor.ObjectThemeColor = msoThemeColorAccent5
Selection.ShapeRange.TextFrame2.TextRange.Font.Fill.ForeColor.TintAndShade = 0
Selection.ShapeRange.TextFrame2.TextRange.Font.Fill.ForeColor.Brightness = -0.5
'set focus back to chart
ActiveSheet.ChartObjects(ActiveChart.Parent.Name).Activate
' Put data lables inside bars
ActiveChart.SeriesCollection(1).ApplyDataLabels
ActiveChart.SeriesCollection(1).DataLabels.Select
Selection.Position = xlLabelPositionInsideEnd
' Put legends at bottom (years)
ActiveChart.Axes(xlCategory).Select
Selection.TickLabelPosition = xlHigh
' Turn off ticks
Selection.MajorTickMark = xlNone
' Delete data legend
ActiveChart.Legend.Select
Selection.Delete
' Delete any data values THAT ARE 0 !
Dim vxVals As Variant
vxVals = ActiveChart.SeriesCollection(1).Values
If vxVals(1) = 0 Then
ActiveChart.SeriesCollection(1).DataLabels.Select
ActiveChart.SeriesCollection(1).Points(1).DataLabel.Select
Selection.Delete
End If
If vxVals(2) = 0 Then
ActiveChart.SeriesCollection(1).DataLabels.Select
ActiveChart.SeriesCollection(1).Points(2).DataLabel.Select
Selection.Delete
End If
If vxVals(3) = 0 Then
ActiveChart.SeriesCollection(1).DataLabels.Select
ActiveChart.SeriesCollection(1).Points(3).DataLabel.Select
Selection.Delete
End If
' We between 5% and 15% let's scootch label down a bit
If vxVals(3) >= 0.05 And vxVals(3) <= 0.15 Then ActiveChart.SeriesCollection(1).DataLabels.Select ActiveChart.SeriesCollection(1).Points(3).DataLabel.Select Selection.Top = Selection.Top + 17 End If If UBound(vxVals) > 3 Then
If vxVals(4) = 0 Then
ActiveChart.SeriesCollection(1).DataLabels.Select
ActiveChart.SeriesCollection(1).Points(4).DataLabel.Select
Selection.Delete
End If
' We between 5% and 15% let's scootch label down a bit
If vxVals(4) >= 0.05 And vxVals(4) <= 0.15 Then
ActiveChart.SeriesCollection(1).DataLabels.Select
ActiveChart.SeriesCollection(1).Points(4).DataLabel.Select
Selection.Top = Selection.Top + 17
End If
End If '
' set focus back to chart
ActiveSheet.ChartObjects(ActiveChart.Parent.Name).Activate
' Change grid lines to light gray
ActiveChart.Axes(xlValue).MajorGridlines.Select
With Selection.Format.Line
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorBackground1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = -0.349999994
.Transparency = 0.5
End With
' Resize to fix boxes
' CHANGE CHART WIDTH AND HEIGHT
' Points, Approx 1/72nd of an Inch
ActiveChart.Parent.Width = (4.6 * 72) '330
ActiveChart.Parent.Height = (2.35 * 72) '169
ActiveSheet.ChartObjects(ActiveChart.Parent.Name).Activate
ActiveChart.PlotArea.Height = 132 ' height before top
ActiveChart.PlotArea.Width = 272
ActiveChart.PlotArea.Left = 4
ActiveChart.PlotArea.Top = 18
'First positioning
ActiveChart.Parent.Left = argL
ActiveChart.Parent.Top = argT
' *********************************************
' COLOR CODED PERCENTILE TEXT BOX DRAWING
' *********************************************
' We need to get values to start adjusting
Dim vChartName
Dim vChartHeight
Dim vChartWidth
Dim vChartLeft
Dim vChartTop
Dim vChartPlotHeight
Dim vChartPlotWidth
Dim vChartPlotLeft
Dim vChartPlotTop
vChartName = ActiveChart.Parent.Name
vChartWidth = ActiveChart.Parent.Width
vChartHeight = ActiveChart.Parent.Height
vChartLeft = ActiveChart.Parent.Left
vChartTop = ActiveChart.Parent.Top
vChartPlotWidth = ActiveChart.PlotArea.Width
vChartPlotHeight = ActiveChart.PlotArea.Height
vChartPlotLeft = ActiveChart.PlotArea.Left
vChartPlotTop = ActiveChart.PlotArea.Top
If argnTile = 4 Then
' Text Box 1
argName = "TB1"
argText = "1st"
argLeft = 5 + vChartPlotWidth + 1
argTop = ActiveChart.PlotArea.Top + 6
argWidth = (ActiveChart.PlotArea.Height / 4) - 7 ' 6 for grid lines?
argHeight = argWidth + 0.2
argR = 0
argG = 176
argB = 80
' Now we have height, can change width
argWidth = argWidth + 5.4
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
argName = "TB2"
argText = "2nd"
argTextColor = "Black"
argHeight = argHeight + 0.5
argR = 146
argG = 208
argB = 80
' Next textbox, top is box on top top + height
argTop = argTop + argHeight - 0.02
' Everything else stays same
On Error Resume Next
ActiveChart.Shapes(argName).Delete
On Error GoTo 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
argName = "TB3"
argText = "3rd"
argHeight = argHeight
argR = 238
argG = 232
argB = 0
' Next textbox, top is box on top top + height
argTop = argTop + argHeight
' Everything else stays same
On Error Resume Next
ActiveChart.Shapes(argName).Delete
On Error GoTo 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
argName = "TB4"
argText = "4th"
argHeight = argHeight - 0.2
argR = 138
argG = 0
argB = 0
argTextColor = "White"
' Next textbox, top is box on top top + height
argTop = argTop + argHeight
' Everything else stays same
On Error Resume Next
ActiveChart.Shapes(argName).Delete
On Error GoTo 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
Else
' *********
' QUINTILES
' *********
' Let place a box to right of plot area
argName = "TB1"
argText = "1st"
argLeft = 5 + vChartPlotWidth + 1
' QUARTILE
'argTop = ActiveChart.PlotArea.Top + 6
' QUINTILE
argTop = ActiveChart.PlotArea.Top + 6
' QUARTILE
'argWidth = (ActiveChart.PlotArea.Height / 4) - 7 ' 6 for grid lines?
' QUINTILE
argWidth = (ActiveChart.PlotArea.Height / 5) - 7 ' 6 for grid lines?
'Debug.Print argWidth
' QUART
'argHeight = argWidth + 0.2
' QUINT
argHeight = argWidth + 0.5
' Now we have height, can change width
argWidth = argWidth + 5.4
' TextBox 1
argR = 0
argG = 153
argB = 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
' QUINTILES !!!! QWER
argName = "TB2"
argText = "2nd"
argTextColor = "Black"
argHeight = argHeight
argR = 146
argG = 208
argB = 80
' Next textbox, top is box on top top + height
argTop = argTop + argHeight + 1.35
' Everything else stays same
On Error Resume Next
ActiveChart.Shapes(argName).Delete
On Error GoTo 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
argName = "TB3"
argText = "3rd"
argHeight = argHeight
argR = 255
argG = 255
argB = 153
' Next textbox, top is box on top top + height
argTop = argTop + argHeight + 1.35
' Everything else stays same
On Error Resume Next
ActiveChart.Shapes(argName).Delete
On Error GoTo 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
argName = "TB4"
argText = "4th"
argHeight = argHeight
argR = 255
argG = 192
argB = 0
argTextColor = "Black"
' Next textbox, top is box on top top + height
argTop = argTop + argHeight + 1.35
' Everything else stays same
On Error Resume Next
ActiveChart.Shapes(argName).Delete
On Error GoTo 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
' QUINT
argName = "TB5"
argText = "5th"
argHeight = argHeight
argR = 192
argG = 0
argB = 0
argTextColor = "White"
' Next textbox, top is box on top top + height
argTop = argTop + argHeight + 1.35
' Everything else stays same
On Error Resume Next
ActiveChart.Shapes(argName).Delete
On Error GoTo 0
CHART_Create_TextBox argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor
End If 'Quartile or Quintile boxes
' *****************
' ADD FOOTNOTE
' *****************
Dim sFootnote As String '
sFootnote = argChartCaption '"* Rankings relative to investment category with smaller percentages indicating better relative performance"
ActiveChart.Shapes.AddTextbox(msoTextOrientationHorizontal, 5, 147, 310, 12).Select
Selection.ShapeRange.TextFrame2.TextRange.Font.Size = 7
Selection.ShapeRange.TextFrame2.TextRange.Font.Italic = True
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = sFootnote
Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, Len(sFootnote)).ParagraphFormat. _
FirstLineIndent = 0
' Format Chart Box
ActiveChart.ChartArea.Select
With ActiveSheet.Shapes("RelPerfRank").Line
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorBackground1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = -0.150000006
.Transparency = 0
End With
ActiveChart.ChartArea.Select
Range("A1").Select
End Sub
Sub CHART_Create_TextBox(argName, argText, argLeft, argTop, argWidth, argHeight, argR, argG, argB, argTextColor)
' Create TEXTBOX L,T,W,H
ActiveChart.Shapes.AddTextbox(msoTextOrientationHorizontal, _
argLeft, _
argTop, _
argWidth, _
argHeight).Name = argName
ActiveChart.Shapes(argName).Select
' Color fill
Selection.ShapeRange.TextFrame2.VerticalAnchor = msoAnchorMiddle
With Selection.ShapeRange.Fill
.Visible = msoTrue
.ForeColor.RGB = RGB(argR, argG, argB) ' DARK GREEN
.Transparency = 0.15
.Solid
End With
' Add Line around box
With Selection.ShapeRange.Line
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorText1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = 0.25
.Transparency = 0.75
End With
' Add Text and Align
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = argText
Selection.ShapeRange.TextFrame2.TextRange.Font.Bold = msoTrue
With Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, 3). _
ParagraphFormat
.FirstLineIndent = 0
.Alignment = msoAlignCenter
End With
With Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, 3).Font
.NameComplexScript = "+mn-cs"
.NameFarEast = "+mn-ea"
.Size = 7
.Name = "+mn-lt"
End With
If argTextColor = "White" Then
With Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, 3).Font.Fill
.Visible = msoTrue
.ForeColor.ObjectThemeColor = msoThemeColorBackground1
.ForeColor.TintAndShade = 0
.ForeColor.Brightness = 0
.Transparency = 0
.Solid
End With
End If
End Sub
Sub CHART_Create_TextBox_Legend(argName, argText, argLeft, argTop, argWidth, argHeight, argFontType, argFontSize, Optional argItalic)
' Create TEXTBOX L,T,W,H
ActiveChart.Shapes.AddTextbox(msoTextOrientationHorizontal, _
argLeft, _
argTop, _
argWidth, _
argHeight).Name = argName
ActiveChart.Shapes(argName).Select
Selection.ShapeRange.TextFrame2.TextRange.Font.Size = argFontSize
Selection.ShapeRange.TextFrame2.VerticalAnchor = msoAnchorMiddle
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = argText
With Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, Len(argText)).ParagraphFormat
.FirstLineIndent = 0
.Alignment = msoAlignLeft
End With
With Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, Len(argText)).Font
.NameComplexScript = "+mn-cs"
.NameFarEast = "+mn-ea"
.Size = argFontSize
.Name = "+mn-lt"
End With
' IsMissing only works with varants
If IsMissing(argItalic) = False Then
If argItalic = True Then
With Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, Len(argText)).Font
.Italic = True
End With
End If
End If
End Sub



