moving average on excel

I have an automated self-updating moving average, which basically is the average of the prices of the last x minutes, polled once per minute.

So this means the macros print price once every minute.

Someone else had written these macros for me years ago, and until now, being an amateur VBA programmer, I still haven't fully understood it.

This would not be a problem, because they work but the reason I want to understand them is to simplify them, because I started off with just one moving average and now I will need about 13 of them, on different markets.

Here's the macros:

1) Everything starts from this macro, which gets started by "ThisWorkbook":

Sub ma_timer()
For i = 1 To 500
ma.Cells(i, 1) = tickers.Cells(12, 20)
Next
TimerOn 60000
End Sub

And this is clear but I don't know what happens next

2) Then we get on another sheet, where I have all these macros:

Private Declare Function SetTimer Lib "User32" _
(ByVal hWnd As Long, ByVal nIDEvent As Long, _
ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long

Private Declare Function KillTimer Lib "User32" _
(ByVal hWnd As Long, ByVal nIDEvent As Long) As Long

Dim averageprice(2) As Double
Dim minutes As Integer
Dim TimerID As Long


Public Sub TimerOn(Interval As Long)
On Error Resume Next
TimerID = SetTimer(0, 0, Interval_eur, AddressOf myroutine)
End Sub

Private Sub myroutine()
On Error Resume Next
minutes = minutes + 1
averageprice(0) = averageprice(0) + tickers.Cells(12, 20)

If minutes = 1 Then
For i = 1 To 499

ma.Cells(i, 1) = ma.Cells(i + 1, 1)

Next
meu.Cells(500, 1) = averageprice(0) / minuti


Erase averageprice
minutes = 0

End If

End Sub



Please let me know if you can help me. It works but I don't know why, and I would like to understand it in order to simplify it and not have these macros multiplied by 13, because it would be too heavy for my CPU.
 
Hi,
For under $100 XLQ provides functions to pull stock/ETF data from a variety of sources (Yahoo, MSN, Google, IB, etc.) as well as providing functions for various moving averages. That's what I use, it's available from qmatix.com
 
Thanks for the information, but this is not what I wanted to do. I didn't get to this point, to just quit using my excel sheet and start something totally new.
 
Sub ma_timer()
For i = 1 To 500
ma.Cells(i, 1) = tickers.Cells(12, 20)
Next
TimerOn 60000
End Sub

Your module streams in 1 ticker at Cells(12,20) and updates then spits out the ma at Cells(i,1).

I won't do all of the work for you , but all you basically need to do is
read different tickers into different cells..
i.e. tickers.Cells(12,20) is streaming 1
tickers2.Cells(13,20) is streaming 2
...
tickersN.Cells(N+12,20) is streaming N

Spit out ma.Cells(i,1)=tickers.Cells(12,20)
ma1.Cells(i,2)=tickers2.Cells(13,20)
..
maN.Cells(i,N)=tickersN.Cells(N+12,20)


You also need to find where the streaming interface tells to pull into
Cells(x,y), and modify it to stream into the aforementioned cells.

You have to be careful about timing, because doing one at a time in loops may have interval lags.

You could look into running the same idea as an array; you'd need to find out how you interface to your provider and how to pull in arrays of data, rather than single quotes.

Hope that helps you. Please don't PM on this one, as I don't have a lot of time to work on this at the moment. Easier to reply on the thread, as everyone learns.
 
Quote from travis:

Thanks for the information, but this is not what I wanted to do. I didn't get to this point, to just quit using my excel sheet and start something totally new.

I neglected to mention that XLQ provides functions available in Excel, so you wouldn't have to stop using your excel sheet. But I understand. I initially looked into to pulling the data myself but just didn't want to put in the time.
 
I'm in a somewhat similar situation although I am using software, Qlink, to feed an array of data into a sheet, then pulling that array into VBA on with a timer loop.

Unfortunately for me the Qlink module is locked, but I am curious how your data feed interfaces with excel.
 
Thanks to dtrader98 and to dwpeters, for the thoughtful advice and feedback.

To bellman and to them I say this. I will now spend a few hours until I figure it all out, and then come back and post an explanation of what my macros do, and which ones I can get rid of and simplify.

So far this is the excel workbook I am working on (see attachment below). It's a simplified version of my systems, which will help me to work specifically on just the moving average.

I am using an excel workbook that uses time instead of price, because it's the weekend so there's no tickers moving. It won't make much difference.

I've identified 4 steps (the 4 macros). Most likely I'll be able to get rid of half of this stuff (one line at a time while verifying that everything still works properly), which will then enable me to simplify the macros and apply them to 13 moving averages, instead of the way it is now where I have these 4 macros multiplied by 13 times (the 13 futures).

This code works perfectly, but as i said the problem is that it's still too complex.
 

Attachments

It works!

Yes!!!

I figured it out, little stupid me...

Here it is, simplified as much as I could:

Private Declare Function SetTimer Lib "User32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long

Sub time_ma()
For i = 1 To 500
ma.Cells(i, 1) = time
Next
TimerID = SetTimer(0, 0, 15000, AddressOf myroutine)
End Sub

Sub myroutine()
On Error Resume Next
For i = 1 To 499
ma.Cells(i, 1) = ma.Cells(i + 1, 1)
Next
ma.Cells(500, 1) = time
End Sub

This link has helped me a lot:
http://vmd.myxomop.com/apires/ref/s/settimer.html

Also, I learned by trial and error.

Now I'll finally be able to implement 13 columns like this one on just one worksheet, and the whole thing will be triggered by just 2 functions instead of 26 functions and 13 sheets.

Here's the final file. I had it run every 15 seconds so I could test its efficacy and debug it a little faster.
 

Attachments

Ok, done. I've copied the whole thing on the paper trading excel workbook, and tomorrow I'll see if it all works out perfectly.

Here's the final code for 9 moving averages.

To explain it out loud to myself, here's what happens.

Private Declare Function...
It uses a function unknown to excel so that it has to call it up from somewhere within windows (excuse my ignorance, I just learned it's called "Windows API"). See here regarding this function:
http://vmd.myxomop.com/apires/ref/s/settimer.html
http://en.wikipedia.org/wiki/Windows_API
http://en.wikipedia.org/wiki/Subroutine

Once the SetTimer function is called (via "private declare function..."), it is used immediately in the first subroutine, "mav", which is actually triggered by a Workbook_Open() subroutine, which I didn't list here because it is simple and it is contained by ThisWorkbook, whereas all the code below is within a module inside the "modules" section (vba menu within excel).


Sub mav()...
In Sub "mav" I do 2 things:

1) I set all cells in my future x-minute price prints to the present price, because in case I need that average sooner than it will be ready, at least it will only be affected by the price at which it was started and not by values of zero or values from previous days

2) I start the timer, telling it to run every x milliseconds (I will need to set it to 5 minutes, I'll do that next)


Sub myroutine()...
Finally here at the last subroutine. This one gets executed every x seconds/minutes as decided by the previous subroutine. Here I do two things:

1) I copy each value of the column to the row above, so everything moves higher by one row, and I keep a record of the previously recorded prices

2) I print the present price (at the time the subroutine is executed) on the last and 500th row of the column. It will be later copied one cell higher and that cell will be available again.


Private Declare Function SetTimer Lib "User32" _
(ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long


Sub mav()
For i = 1 To 500
ma.Cells(i, 1) = Sheet1.Cells(12, 20)
ma.Cells(i, 2) = Sheet1.Cells(13, 20)
ma.Cells(i, 3) = Sheet1.Cells(14, 20)
ma.Cells(i, 4) = Sheet1.Cells(15, 20)
ma.Cells(i, 5) = Sheet1.Cells(16, 20)
ma.Cells(i, 6) = Sheet1.Cells(17, 20)
ma.Cells(i, 7) = Sheet1.Cells(18, 20)
ma.Cells(i, 8) = Sheet1.Cells(19, 20)
ma.Cells(i, 9) = Sheet1.Cells(20, 20)
Next
TimerID = SetTimer(0, 0, 15000, AddressOf myroutine)
End Sub


Sub myroutine()
On Error Resume Next
For i = 1 To 499
ma.Cells(i, 1) = ma.Cells(i + 1, 1)
ma.Cells(i, 2) = ma.Cells(i + 1, 2)
ma.Cells(i, 3) = ma.Cells(i + 1, 3)
ma.Cells(i, 4) = ma.Cells(i + 1, 4)
ma.Cells(i, 5) = ma.Cells(i + 1, 5)
ma.Cells(i, 6) = ma.Cells(i + 1, 6)
ma.Cells(i, 7) = ma.Cells(i + 1, 7)
ma.Cells(i, 8) = ma.Cells(i + 1, 8)
ma.Cells(i, 9) = ma.Cells(i + 1, 9)
Next
ma.Cells(500, 1) = Sheet1.Cells(12, 20)
ma.Cells(500, 2) = Sheet1.Cells(13, 20)
ma.Cells(500, 3) = Sheet1.Cells(14, 20)
ma.Cells(500, 4) = Sheet1.Cells(15, 20)
ma.Cells(500, 5) = Sheet1.Cells(16, 20)
ma.Cells(500, 6) = Sheet1.Cells(17, 20)
ma.Cells(500, 7) = Sheet1.Cells(18, 20)
ma.Cells(500, 8) = Sheet1.Cells(19, 20)
ma.Cells(500, 9) = Sheet1.Cells(20, 20)
End Sub
 
Quote from travis:

Ok, done. I've copied the whole thing on the paper trading excel workbook, and tomorrow I'll see if it all works out perfectly.

There's a lot of scope for re-factoring the code. You could start by removing the repetitive code and replacing it with some loops:

Code:
Sub mav()
    For i = 1 To 500
		For j = 1 To NoOfSymbols
			ma.Cells(i, j) = Sheet1.Cells(11 + j, 20)
        Next
    Next
    TimerID = SetTimer(0, 0, 15000, AddressOf myroutine)
End Sub


Sub myroutine()
    On Error Resume Next
	
    For i = 1 To 499
		For j = 1 To NoOfSymbols
			ma.Cells(i, j) = ma.Cells(i + 1, j)
		Next
    Next
	
	For j = 1 To NoOfSymbols
		ma.Cells(500, j) = Sheet1.Cells(11 + j, 20)
	Next
End Sub

Obviously you'll have to declare NoOfSymbols somewhere and set it to 9 but now you can change the number of symbols just by changing that declaration. Perhaps you can even read the value from a cell on your spreadsheet so all you have to do is change the cell.

"myroutine" isn't a very good name for a routine. Perhaps rename it to something more meaningful - what is that routine doing exactly?

What is the 500? Is that the number of periods? That should also be factored out as a variable or constant declared somewhere.

There is still some repetition of code in the version I posted so there's still room for improvement.
 
Back
Top