Reputation: 1
I am pretty new to VBA hence my current struggle and clumsy code. Within my code I am trying identify uncorrelated stocks for a study project. The idea is that my macro generates a correlation matrix, bounded the Stock Names and then loops through line by line to return the most "uncorrelated" stock for the underlying sample. However, I do not currently know whether there is just a referencing issue in my code or whether there is any fundamental issue. Any help would be much appreciated
Find below the relevant part of the script:
Sub Test()
Dim Names As Variant
Dim Ref As Variant
Set Names = Worksheets("Correlation Matrix").Range(Cells(1, 3), Cells(1, Stocks))
For i = 1 To Stocks
Worksheets("Correlation Matrix").Activate
Ref = Worksheets("Correlation Matrix").Range(Cells(i + 1, 3), Cells(i + 1, Stocks)).Value
Worksheets("Main").Activate
Worksheets("Main").Cells("O" & i + 4).FormulaArray = "=Index(" & Names.Address & ",MATCH(MIN(ABS(" & Ref.Address & " - 0),ABS(" & Names.Address & "- 0),0))"
Next i
End Sub
The "Correlation Matrix" worksheet looks like this:
Disney Microsoft Apple sp500 Disney 1 0.764790855 0.737566223 0.832602399 Microsoft 0.764790855 1 0.754724823 0.827980429 Apple 0.737566223 0.754724823 1 0.90982066 sp500 0.832602399 0.827980429 0.90982066 1
Upvotes: 0
Views: 75
Reputation: 338406
Consider this approach:
In the correlation matrix, we only need to look at the numbers either "above" or "below" the diagonal line of "1"s. All other values are just a mirror image, looking at them would be a waste of time.
So we try to look at a triangle of coordinates:
A (1) B (2) C (3) D (4) E (5) 1 Disney Microsoft Apple sp500 2 Disney 1 0.764790855 0.737566223 0.832602399 3 Microsoft 0.764790855 1 0.754724823 0.827980429 4 Apple 0.737566223 0.754724823 1 0.90982066 5 sp500 0.832602399 0.827980429 0.90982066 1
Excel also counts columns from 1, that's what the numbers in the parenthesis are. The row-column coordinates we want to inspect could be the "lower" half, like this (the "x" marks the diagonal cells with value 1):
A (1) B (2) C (3) D (4) E (5) 1 2 x 3 (3,2) x 4 (4,2) (4,3) x 5 (5,2) (5,3) (5,4) x
A nested loop can create those coordinate pairs. The loop runs for rows 3..5 and columns 2..4, respectively, but it excludes any columns outside of the "triangle":
Sub LeastCorrelated(NumStocks As Integer)
Dim corrMatrix As Worksheet
Dim minimumCell As Range, cell As Range
Dim r As Integer, c As Integer
Dim stock1 As String, stock2 As String
Set corrMatrix = Worksheets("Correlation Matrix")
Set minimumCell = corrMatrix.Cells(2, 2) ' the top-left cell containing "1"
For r = 3 To NumStocks + 1
For c = 2 To r - 1
Set cell = corrMatrix.Cells(r, c)
If cell.Value < minimumCell.Value Then Set minimumCell = cell
Next
Next
minimumCell.Select
stock1 = corrMatrix.Cells(1, minimumCell.Column).Value
stock2 = corrMatrix.Cells(minimumCell.Row, 1).Value
Debug.Print stock1 & " / " & stock2
End Sub
When called as
LeastCorrelated 4
this prints
Disney / Apple
and selects cell A4.
Upvotes: 1
Reputation: 27269
Dimension the variables as Range
objects. Variant
is a catch all data type and does not have a .Name
property.
See below. I also changed Names
variable since .Names
refers to named ranges.
Sub Test()
Dim theNames As Range
Dim Ref As Range
Set theNames = Worksheets("Correlation Matrix").Range(Cells(1, 3), Cells(1, Stocks))
For i = 1 To Stocks
'Worksheets("Correlation Matrix").Activate - no need to activate sheet
Set Ref = Worksheets("Correlation Matrix").Range(Cells(i + 1, 3), Cells(i + 1, Stocks)).Value
'Worksheets("Main").Activate - no need to activate sheet
Worksheets("Main").Cells("O" & i + 4).FormulaArray = "=Index(" & theNames.Address & ",MATCH(MIN(ABS(" & Ref.Address & " - 0),ABS(" & theNames.Address & "- 0),0))"
Next i
End Sub
Upvotes: 0