PureBytes Links
Trading Reference Links
|
With all the talk about standard deviations on this list, I thought
I'd mention an update I just completed today.
For quite a while I've had EL code for an exponential moving
standard deviation. I implemented it because I wanted something
that recovers from data outliers more quickly than the traditional
standard deviation (just one outlier will pollute the traditional
one for all of N bars).
The 1-liner I came up with came from an article in a statistics
journal somewhere. It worked great, extremely fast, except it
seemed to work only when the mean of data was very small. If you
tried to use it on, say, price, the results were way off. Using it
on something like daily range worked fine.
Finally today I got around to deriving my own exponential moving
standard deviation that doesn't assume zero mean to the distribution
of data. It's a 3-liner, still extremely fast, using no loops.
I've tested it and it seems to work fine. It approximates the
"biased" or n-weighted Population Standard Deviation rather than
the (n-1)-weighted Sample Standard Deviation that everyone uses.
Fortunately these two formulas are approximately equal when n
is large enough (like >20). I found it impossible to derive an
exponential version of the (n-1)-weighted deviation.
I've updated my page http://unicorn.us.com/trading/el.html with
this new version, and I include the code below, complete with my
derivation in the comments.
----------------------------------------------------------------------
{_xStdDev Exponential moving standard deviation
by Alex Matulich alex@xxxxxxxxxxxxxx 4/2003
_xStdDev(x,n) returns a good approximation of the standard deviation
of n values of x. In _xStdDev the terms have exponential weight so
the function reacts faster, and recovers from outliers more quickly
than the traditional standard deviation. This makes it well-suited
for use in time series analysis.
Derivation of the Exponential Moving Standard Deviation
-------------------------------------------------------
The formula for the sample standard deviation is:
StdDev = SquareRoot[(n*sum(x^2) - sum(x)^2) / (n*(n-1))]
We can simplify this by using the "biased" or population standard
deviation by replacing n-1 in the denominator with n:
StdDevP = SquareRoot[(n*sum(x^2) - sum(x)^2) / n^2]
For large n (and it doesn't have to be that large), StdDev = StdDevP
approximately. We'll assume the simpler StdDevP is good enough.
Then distributing the denominator to each term, we re-write it as:
StdDevP = SquareRoot[sum(x^2)/n - (sum(x)/n)^2]
Knowing that sum()/n = average(), we have:
StdDevP = SquareRoot[average(x^2) - average(x)^2]
At this point we can substitute an exponential moving average for
the arithmetic average, and arrive at an exponential approximation
of the population standard deviation.
If your data are distributed such that the mean hovers around zero,
then the following 1-line calculation will work just fine:
_xStdDev0 = SquareRoot(w0*price*price + w1*_xStdDev0[1]*_xStdDev0[1])
}
Inputs:
x(NumericSeries), {price data}
length(NumericSimple); {"lookback" length; can change mid-stream}
Vars:
w0(0), w1(0), {exponential weights}
xlen(0), {used to detect changes in length}
avx(0), avx2(0); {average of x and average of x^2}
if xlen <> length or CurrentBar <= 1 then begin
w0 = 2 / (length + 1);
w1 = 1 - w0;
xlen = length;
if Currentbar <= 1 then begin
avx = x;
avx2 = x*x;
end;
end;
avx = w0*x + w1*avx[1]; {exponential average of x}
avx2 = w0*x*x + w1*avx2[1]; {exponential average of x^2}
{The square root argument should never be negative, but if it does
ever go negative for some reason, then uncomment the following line.}
{if xp*xp > xp2 then xp = SquareRoot(xp2);}
_xStdDev = SquareRoot(avx2 - avx*avx);
----------------------------------------------------------------------
--
,|___ Alex Matulich -- alex@xxxxxxxxxxxxxx
// +__> Director of Research and Development
// \
// __) Unicorn Research Corporation -- http://unicorn.us.com
|