PureBytes Links
Trading Reference Links
|
Hi,
There are several different sorting algorithms available. Just do a
web search.
In the sample below, I illustrate the concept using a bubble sort.
Note that while bubble sort is perhaps the easiest to understand, it
is one of the least efficient algorithms. Further, there are more
efficient implementations of bubble sort than the one shown below.
But, this is the most straight forward.
The sample also illustrates the idea of copying a subset of elements
with which to work on. Again, it would have been more efficient
to have passed the original array along with a start index and length
argument to avoid the copy entirely.
Finally, I've implemented median which returns a scaler and uses the
average of the two middle numbers when dealing with an even set. Note
that none of the code below is robust enough to handle Null values
and has not been extensively tested.
As to your last question, in my usage, the impact of leading nulls is
so minimal as to not warrant any special treatment. Particularly when
dealing with long histories of data.
Mike
// BubbleSort Adapted from WikiPedia article
// http://en.wikipedia.org/wiki/Bubble_sort
function bubbleSort( A, length )
{
do
{
swapped = false;
for ( i = 0; i < length - 1; i++ )
{
if ( A[i] > A[i + 1] )
{
temp = A[i + 1];
A[i + 1] = A[i];
A[i] = temp;
swapped = true;
}
}
}
while ( swapped );
return A;
}
function myMedian( A, length )
{
A = bubbleSort( A, length );
if ( length % 2 )
{
result = A[floor( length/2 )];
}
else
{
mid = ( length / 2 ) - 1;
result = ( A[mid] + A[mid + 1] ) / 2;
}
return result;
}
Period = Param( "Period", 20 );
P = Period - 1;
Exponent = 2 / ( Period + 1 );
for ( i = 0; i < BarCount; i++ )
{
if ( i < P )
{
for ( j = 0; j <= i; j++ )
{
A[j] = Close[j];
}
MyEMA[i] = myMedian( A, i + 1 );
}
else
{
MyEMA[i] = ( Close[i] * Exponent ) + ( MyEMA[i - 1] * ( 1 -
Exponent ) );
}
}
Plot( EMA( Close, 20 ), "EMA", colorGreen );
Plot( MyEMA, "MyEMA", colorBlue );
Plot( Close, "Close", colorRed );
--- In amibroker@xxxxxxxxxxxxxxx, "searnp" <searnp@xxx> wrote:
>
> Mike,
>
> Thank you very much! Works as intended.
>
> Thanks also for noting about how median is calculated, I prefer the
> convention of taking the average of the two middle values as well.
I do
> not know how to do the sorting like you mentioned, but when I was
> reading the user guide trying to figure out how to do such a sort I
> stumbled onto the percentile function which does do the averaging
method
> for the 50th percentile. So I got lucky in that respect. If you are
> willing though, I am interested in learning how a sort would be
done to
> accomplish this.
>
> Sorry to bother you again, but another question:
> If am doing the calculation off an array that has null values for
the
> first "x" number of bars (i.e. if running the calculating off of
true
> range, it would be null at bar 0 since there is no prior day's
close),
> the null value is carried through the calculation's entire array. Is
> there a way to automatically adjust for that instead of manually
> adjusting the calculation for a given array?
>
> Thanks again.
>
>
>
>
> --- In amibroker@xxxxxxxxxxxxxxx, "Mike" <sfclimbers@> wrote:
> >
> > Sorry, for the fully parameterized solution, replace the line:
> >
> > Plot(EMA(Close, 20), "EMA", colorGreen);
> >
> > With
> >
> > Plot(EMA(Close, Period), "EMA", colorGreen);
> >
> > Mike
> >
> > --- In amibroker@xxxxxxxxxxxxxxx, "Mike" sfclimbers@ wrote:
> > >
> > > This won't be the fastest implementation, but I believe that it
> > will
> > > work. Assuming a period of 20...
> > >
> > > 1. Let P = Period - 1 (e.g. 20 - 1 = 19)
> > > 2. Make P calls to the AFL Median function using 1..P (e.g.
1..19)
> > as
> > > the period scaler.
> > > 3. Store the P-1th value for each result in a dynamic variable
of
> > the
> > > same name. P-1 will be the first zero indexed, non null value
for
> > > each array. You should end up with:
> > >
> > > M0 = Median(Close, 1)[0];
> > > M1 = Median(Close, 2)[1];
> > > ...
> > > M18 = Median(Close, 19)[18];
> > >
> > > 4. Write a loop to set the first P values to the dynamic
variables
> > > and calculate a regular EMA for the remainder. Your chart should
> > > converge quickly after the first Period bars.
> > >
> > > e.g.
> > >
> > > Period = Param("Period", 20);
> > >
> > > // Calculate dynamic median for initial Period-1 bars, stored as
> > > // dynamic variables M0, M1, ..., MP where P = Period - 1.
> > >
> > > P = Period - 1;
> > >
> > > for (i = 0; i < P; i++) {
> > > M = Median(Close, i + 1);
> > > VarSet("M" + i, M[i]);
> > > }
> > >
> > > // Calculate EMA substituting our dynamic variables for the
first
> > > // Period - 1 values.
> > >
> > > Exponent = 2/(Period + 1);
> > >
> > > for (i = 0; i < BarCount; i++) {
> > > if (i < P) {
> > > MyEMA[i] = VarGet("M" + i);
> > > } else {
> > > MyEMA[i] = (Close[i] * Exponent) + (MyEMA[i - 1] * (1 -
> > > Exponent));
> > > }
> > > }
> > >
> > > Plot(EMA(Close, 20), "EMA", colorGreen);
> > > Plot(MyEMA, "MyEMA", colorBlue);
> > > Plot(Close, "Close", colorRed);
> > >
> > > Note that there appears to be a bug in AmiBroker (else in my
code!)
> > > such that Median is not being correctly calculated when there
are
> > an
> > > even number of values. The correct Median value of an even set
of
> > > numbers is the average of the two middle values. However,
AmiBroker
> > > appears to be returning the first of the two middle values,
> > ignoring
> > > the second of the two middle values.
> > >
> > > Alternatively, you could calculate the Median yourself using an
> > inner
> > > loop to fill a temporary array which you would then pass to a
> > sorting
> > > function and your own Median implementation. This would have the
> > > advantage of operating only on a maximum of Period values
(instead
> > of
> > > all visible values), but would not be in binary code as the
built
> > in
> > > Median is.
> > >
> > > Mike
> > >
> > > --- In amibroker@xxxxxxxxxxxxxxx, "searnp" <searnp@> wrote:
> > > >
> > > > Bump
> > > >
> > > > --- In amibroker@xxxxxxxxxxxxxxx, "searnp" <searnp@> wrote:
> > > > >
> > > > > Hi Howard, thanks for your reply.
> > > > >
> > > > > I am looking at calculating an exponential moving average,
but
> > > would
> > > > > like to have initial values as well (instead of null
values).
> > > > >
> > > > > For example:
> > > > > If I do an EMA(Close, 20), I will get a chart of the 20-day
EMA
> > of
> > > > > close with null values for the first 20 bars.
> > > > >
> > > > > So what I am trying to do is create my own EMA function via
> > > looping
> > > > > (similar to pg.114 of the Amibroker User Guide), where the
> > running
> > > > > median would be calculated for (i + 1) < Period. I can do it
> > with
> > > an
> > > > > initial simple running average calculation (since I can
> > > incorporate
> > > > > that in the loop for (i + 1) < Period ), but would prefer to
> > use
> > > the
> > > > > median in case there are initial spikes.
> > > > >
> > > > > Another question loosely related to this:
> > > > > When I incorporate a manual bar count via looping (see code
> > > below) and
> > > > > then click on a bar on the chart, the value changes when I
> > scroll
> > > left
> > > > > or right or zoom in or out. Why is this?
> > > > >
> > > > > CT[0] = 1;
> > > > > for( i = 1; i < BarCount; i++ )
> > > > > {
> > > > > CT[i] = 1 + CT[i-1];
> > > > > }
> > > > >
> > > > > Plot( CT, _DEFAULT_NAME(), ParamColor( "Color",
colorCycle ),
> > > > > ParamStyle("Style") );
> > > > >
> > > > >
> > > > > Thanks.
> > > > >
> > > > > --- In amibroker@xxxxxxxxxxxxxxx, "Howard B" <howardbandy@>
> > wrote:
> > > > > >
> > > > > > Hi Searnp --
> > > > > >
> > > > > > The User's Guide states:
> > > > > > AFL Function Reference - MEDIAN *MEDIAN
> > > > > > *- calculate median (middle element)
> > > > > >
> > > > > > *Statistical functions
> > > > > > *(AFL 2.5)
> > > > > >
> > > > > > *SYNTAX* *Median( array, period ) * *RETURNS* ARRAY
> > > *FUNCTION*
> > > > > The Median
> > > > > > function - finds median (middle element) value of the
*array*
> > > over
> > > > > > *period*elements.
> > > > > > *EXAMPLE* // list only symbols which volume is greater
than
> > > > > > // median Volume from past 50 days
> > > > > > *Filter* = *Volume* > Median( *Volume*, 50 );
> > > > > > AddColumn( *V*, "Volume" );
> > > > > > Period must be a scalar -- a constant. When you run this
> > code:
> > > > > >
> > > > > > RM = Median(Close, BarIndex() + 1);
> > > > > >
> > > > > > The entire Close array is passed to the Median function at
> > one
> > > time.
> > > > > The
> > > > > > value of BarIndex changes with each element of the Close
> > array.
> > > > > Looked at
> > > > > > simplistically, the afl processor does not know which
value of
> > > > > BarIndex to
> > > > > > use, so it coughs.
> > > > > >
> > > > > > You will have to write your own function using looping
code.
> > > > > >
> > > > > > Before you start, are you certain that you want the median
> > > value of an
> > > > > > expanding list of data values? Today's value will depend
on
> > how
> > > > > much data
> > > > > > was loaded, which is generally not a good programming or
> > systems
> > > > > idea. Will
> > > > > > Median(C,50), or some variation, give you what you need?
> > > > > >
> > > > > > Thanks,
> > > > > > Howard
> > > > > >
> > > > > >
> > > > > >
> > > > > > On Mon, Nov 3, 2008 at 11:26 AM, searnp <searnp@> wrote:
> > > > > >
> > > > > > > I am trying to calculate a running median that starts
at
> > > bar 0.
> > > > > > >
> > > > > > > Code:
> > > > > > >
> > > > > > > RM = Median(Close, BarIndex() + 1);
> > > > > > >
> > > > > > >
> > > > > > > Then I get the following error message:
> > > > > > >
> > > > > > > Error 5. Argument #2 has incorrect type (the function
> > expects
> > > > > different
> > > > > > > argument type here)
> > > > > > >
> > > > > > >
> > > > > > > I am using "Barindex() + 1" to get a running count at
each
> > > bar to
> > > > > be used
> > > > > > > in the median's lookback period. Is there a way to
> > implement
> > > this?
> > > > > > >
> > > > > > > Thanks.
> > > > > > >
> > > > > > >
> > > > > >
> > > > >
> > > >
> > >
> >
>
------------------------------------
**** IMPORTANT ****
This group is for the discussion between users only.
This is *NOT* technical support channel.
*********************
TO GET TECHNICAL SUPPORT from AmiBroker please send an e-mail directly to
SUPPORT {at} amibroker.com
*********************
For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
http://www.amibroker.com/devlog/
For other support material please check also:
http://www.amibroker.com/support.html
*********************************
Yahoo! Groups Links
<*> To visit your group on the web, go to:
http://groups.yahoo.com/group/amibroker/
<*> Your email settings:
Individual Email | Traditional
<*> To change settings online go to:
http://groups.yahoo.com/group/amibroker/join
(Yahoo! ID required)
<*> To change settings via email:
mailto:amibroker-digest@xxxxxxxxxxxxxxx
mailto:amibroker-fullfeatured@xxxxxxxxxxxxxxx
<*> To unsubscribe from this group, send an email to:
amibroker-unsubscribe@xxxxxxxxxxxxxxx
<*> Your use of Yahoo! Groups is subject to:
http://docs.yahoo.com/info/terms/
|