DGW & others,
I think the question and the answer are not matching up here. DGW, what you are looking for is the 'technician' or risk managers version of a moving average that weights more recent periods higher than others with the ability to control the length of the window via a parameter.
I created a subroutine that does this and it is posted below. Note that you will need to come up with a way to find the first and last available values of your series and pass them in (i didn't give that code in this example but am happy to post it if anyone is interested).
I note this in the code, but here, for clarity, this function takes a window argument (same as #per in @movav(%series, #per)) and a lambda, or decay, coefficient. if the decay coefficient = 1, then you just have a moving average. if the decay coefficient = 0 then you just have the prior period's value. So scale it 0 to 1 (most that I see in practice are >.85). This is like hitting this problem with a very large sledge hammer, but I know of no other way to tackle it. the calc time is necessarily a function of the window but it shouldn't be too onerous for reasonably sized series and projects.
DGW, hope the code answers your original query. If you have found a cleaner way to calculate, would love to see it.
p.s. I went ahead and posted the first/last date available code as well.
Code: Select all
'this routine will calculate the Exponentially Weighted
'Moving Average for a given window for a specified
'series. Must specify a lambda coefficient between
'0 and 1.
'formula courtesy of book: Market Models by Carol Alexander
'forumla is as follows:
'Numerator/Denominator
'Where:
'Numerator = x(t-1) + !coeff*x(t-2) + !coeff^2*x(t-3) + ...+!coeff^(n-1)*x(t-n)
'Denominator = 1+!coeff+coeff^2+...+!coeff^(n-1)
'x = the series you are calculating the ewma on.
'!coeff is the lambda coefficient to control the speed of decay for older values.
'If !coeff = 1 then you have an equally weighted moving average.
'If !coeff = 0 then you just have the prior value.
'include a routine to find the first and last dates of data for a series..more on that later.
include m:\toolbox\findfactorstartenddates.prg
'specify the parameters.
Subroutine Calc_EWMA(scalar !coeff, scalar !window, string %series, string %suffix)
'where:
'!coeff = lambda
'!window = the duration of the moving average (10dma, 50dma, etc.)
'%series = the name of the series that you are calculating the ewma for.
'%suffix = the string to append to the series name to designate the new ewma series.
'full sample
smpl @all
'****************************************************
'this section deals with finding the first and last available
'data for a given series. I do not know of EVIEWS6 way of
'doing this with a function. So I created a subroutine that
'I use in all sorts of routines.
group temp totmkus
%group = "temp"
'the input is a group that contains all of the
'series that I want to get start and end dates for.
call findfactorstartenddates(%group)
'the output of my routine is a table called _starteneddate
'the first available date is in column 2 and the last available date is in
'column 3.
!first = @dtoo(_startenddate(1, 2))
!last = @dtoo(_startenddate(1,3))
'*****************************************************
'at this point you need to have the observation number for your
'first and last available data point.
'create the name of the new series we will use.
%ewma = %series+@str(!window)+"dewma"
'delete if it already exists.
if @isobject(%ewma) then
delete {%ewma}
endif
'create the series.
series {%ewma}
'equal weighted moving average
'move through every point in time in a loop.
For !i = (!first+!window) to !last
!num = 0 'initialize
!den = 0 'initialize
'loop through the ewma window time frame.
for !n = 1 to !window
'note that on first loop exponent = 0
'so first value of numerator & denominator
'are = 1
!num = !num + {%series}(!i-!n)*!coeff^(!n-1)
!den = !den + !coeff^(!n-1)
next
'now create the Exp. Wgtd. Mvavg
{%ewma}(!i) = !num/!den
next
Endsub
'for testing. if calling from another program, just comment this line.
call calc_ewma(.9, 10, "totmkus", "dewma")
*********************************************************
And the code for the first/last date available.
you will need to save as a subroutine. Pass in your series in
a group.
********************************************************
Code: Select all
Subroutine FindFactorStartEndDates(string %grp_list)
'this program takes a list of factors and finds the start day for each one.
'this is helpful when building a model with short tailed factors. Which ones
'have the most data available??
'what is the group name for the factor list?
%FactorList = %grp_list
'A talbe named _StartDate will be used to record the factor names and start
'dates. if it exists, delete it to avoid confusion.
if @isobject("_StartEndDate") then
delete _StartEndDate
endif
'Build a trend variable to determine how many observations there are.
If @isobject("_trend") then
delete _trend
endif
Series _trend = @trend()
'now create _startdate
Table _StartEndDate
'Find the number of factors in the list
!LastFactor = {%FactorList}.@count
For !j = 1 to !LastFactor
%Factor = {%FactorList}.@seriesname(!j)
for !i = 1 to @obs(_Trend)
if @isna({%Factor}(!i)) = 0 then
For !k = !i to @obs(_Trend)
If @isna({%Factor}(!k))=1 then
'the prior date is the last
_StartEndDate(!j,3) = @otod(!k-1)
exitloop
endif
next
exitloop
endif
next
_StartEndDate(!j,2) = @otod(!i)
_StartEndDate(!j,1) = %factor
next
'clean up.
if @isobject("_trend") then
delete _trend
endif
EndSub
'for testing
'call findfactorstartenddates("a3myieldmo")