MACD VBA

This post includes links to two example xls files that show both VBA and Formula based calculations for the indicator MACD or Moving Average Convergence Divergence.

Both files contain the exact same set of Open High Low Close data. The formula based version is easier to understand and serves as a way to verify that the VBA code that I wrote is correct. Both methods give the same result.  The major benefit of using VBA is that the parameters for MACD can be easy changed from the input boxes. In addition the VBA method shows only the final result rather than take up five columns.

The VBA based version can be downloaded here.

The formula version can be downloaded here. Below is the code from the VBA based version.

Sub ETmacd() 'written by Exceltrader www.exceltrader.net
Dim EMAslow As Double, EMAfAst As Double, ws As Worksheet, LR As Integer
Dim eMaF() As Double, eMaS() As Double, EMAdif(), emaPer() As Double, MacDper As Double, coUnt As Integer
Dim DataRange As Range
Dim ExPSlowWeight As Double
Dim ExPFastWeight As Double
Dim PerWeight As Double
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''  The below three lines are the MACD settings.                                         ''
''  The Values can either be changed here or uncomment the inputbox lines to be prompted.''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
EMAslow = 13 'InputBox(Prompt:="Enter Macd Slow settings.", Title:="MACD SLOW", Default:="13")
EMAfAst = 5 'InputBox(Prompt:="Enter Macd Fast settings.", Title:="MACD Fast", Default:="5")
MacDper = 6 'InputBox(Prompt:="Enter Macd Period settings.", Title:="MACD Period", Default:="6")
ExPSlowWeight = 2 / (EMAslow + 1)
PerWeight = 2 / (MacDper + 1)
ExPFastWeight = 2 / (EMAfAst + 1)
Set ws = ThisWorkbook.Worksheets("VBA") 'or use exact sheet name for example ThisWorkbook.worksheet("Sheet1")
'slow
    With ws
    LR = .Cells(Rows.coUnt, "A").End(xlUp).Row
        For Each DataRange In ws.Range(.Cells(2, "A"), .Cells(LR, "A"))
        coUnt = DataRange.Row + 1
        'fill the eMA slow Array
        ReDim Preserve eMaS(1 To coUnt)
                If coUnt = EMAslow + 1 Then
                    'get the first value which is the Simple Moving average
                     eMaS(coUnt) = Application.Average(ws.Range(.Cells(2, "E"), .Cells(coUnt, "E")))
                ElseIf coUnt > EMAslow Then
                    eMaS(coUnt) = (.Cells(coUnt, "E") * ExPSlowWeight) + (eMaS(coUnt - 1) * (1 - ExPSlowWeight))
                End If
        Next DataRange
'fast
        For Each DataRange In ws.Range(.Cells(2, "A"), .Cells(LR, "A"))
        coUnt = DataRange.Row + 1
        'fill the eMA slow Array
        ReDim Preserve eMaF(1 To coUnt)
                If coUnt = EMAfAst + 1 Then
                    'get the first value which is the Simple Moving average
                     eMaF(coUnt) = Application.Average(ws.Range(.Cells(2, "E"), .Cells(coUnt, "E")))
                ElseIf coUnt > EMAfAst Then
                    eMaF(coUnt) = (.Cells(coUnt, "E") * ExPFastWeight) + (eMaF(coUnt - 1) * (1 - ExPFastWeight))
                End If
        Next DataRange
        ReDim Preserve EMAdif(EMAslow To UBound(eMaF))
            For coUnt = EMAslow + 1 To UBound(eMaF)
                EMAdif(coUnt) = eMaF(coUnt) - eMaS(coUnt)
            Next coUnt
'MacD Period
        Dim x As Integer, y As Integer, z As Integer, Avee As Double
        y = EMAslow + MacDper - 1
            For x = y To UBound(EMAdif) - 2
                'get the SMA for first value
                If x = y Then
                        For z = EMAslow + 1 To EMAslow + MacDper  '(EMAslow + MacDper - 1)
                        Ave = Ave + EMAdif(z)
                        Next z
                        ReDim emaPer(x To LR)
                        emaPer(x) = Ave / MacDper
                ElseIf x > y Then
                emaPer(x) = (EMAdif(x + 1) * PerWeight) + (emaPer(x - 1) * (1 - PerWeight))
                End If
            Next x
  x = Empty: y = Empty: z = Empty
  x = LBound(emaPer)
  y = UBound(emaPer)
  For z = x To y - 1
  .Cells(z + 1, "J") = EMAdif(z + 1) - emaPer(z)
  Next z
End With
End Sub 'written by Exceltrader www.exceltrader.net

How to add an indicator to Simulator.xls Chart (or any Excel Stock Chart).

If you have ever tried to add a simple moving average (or any data series) to a stock chart you may have noticed that after adding the series, the chart got all messed up!

Here is a short tutorial and an example file showing how to add a simple moving average to a stock chart. I am going to use the Simulator.xls as and example. It should be noted that all the unused columns on the BarData sheet (currently K-IV) of the simulator can be used to add indicators of your choice.

Trick number one. the =NA() trick

To plot a simple moving average (SMA), the formula is =AVERAGE(E132:E150)

So that would go in R150 on BarData Sheet.

There is a problem though. Excel will try to plot something when there is not enough data to average or even when there is an error. Here is an example of a chart we are trying to avoid.

ind11

The keep the chart clean, I want to generate the error NA# whenever I do not want anything plotted.

so to keep things looking right, change the formula in R150 to =IF(ISBLANK(E132),NA(),AVERAGE(E132:E150))

which means:

“If there is not enough data for this simple moving average, then give me NA# (so excel does not plot anything) otherwise just calculate the average.”

Next just drag and copy this formula from R150 up to R19 (the first cell where it is possible to have enought data to calculate the average!)

Now all that is left is to add this moving average to the chart. It’s surprisingly tricky though.

1. Right click on the chart and select “source data”

the following screen comes up. Click on “add” and fill it in as follows. (make sure there are some numbers in column R)

ind2

2. Select OK and take a look at the chart. Things should look funny on the chart now. Don’t worry about it, just find the data series “indicator”. It should be somewhere on the chart. In my case it plotted this price moving average on the secondary axis which is volume!

Hover your mouse around the volume series looking for “indicator”. Right click on the “indicator” series and change it to primary axis from secondary axis (which will be hidden somewhere down in the volume bars if it’s on the secondary axis. It can be hard to find/click on, if it is you may want to zoom in)

ind31

Now “indicator” should be plotted up there with price, but now the price chart will be all messed up!!!!!! (see how the first bar is missing parts!)

ind4

Next you once again need to hover your mouse around the price series looking for “indicator” when indicator is visible, right click on it and select “chart type”.

The following screen comes up and just select XY (Scatter) as shown and press OK.

ind5

Now the chart will look normal again.

ind6

The last step is to properly format this scatter chart to look like a line. For the last time find the “indicator” series on the chart and right click on it. This time select “format data series” and set it as follows.ind7

Select “OK” and the resulting indicator should like like this.

ind8

One final tip.

Use google! If you are wanting to add a stochastic indicator for example, but don’t know how to calculate it. Try the following search:

stochastic filetype:xls

This will return tons of Excel files described with the word stochastic. There is a good chance that you will find a nice example there. If you have no luck, next you should search investopedia.com, which often explains the calculations.