average true range

B

Bill Cunningham

I have create these 2 files. Called main.c and atr.c. They seem to work
pretty well. I just wanted to submit them to see what if any errors others
that know more might find. Thanks.

atr.c

#include <stdio.h>

double
atr (double th, double tl, double wc)
{
if (th - tl > th - wc && tl - wc < th - tl)
{
return th - tl;
}
if (th - wc > th - tl && tl - wc < th - wc)
{
return th - wc;
}
if (tl - wc > th - wc && th - tl < tl - wc)
{
return tl - wc;
}

}

main.c

#include <stdio.h>
#include <stdlib.h>

extern double atr ( double th, double tl, double wc );

int
main (int argc, char *argv[])
{
if (argc != 4)
{
fprintf (stderr, "usage error th, tl, wc\n");
exit (EXIT_FAILURE);
}
double th, tl, wc;
th = strtod (argv[1], NULL);
tl = strtod (argv[2], NULL);
wc = strtod (argv[3], NULL);
printf("%.2f\n", atr(th, tl, wc));

}

Bill
 
B

Bill Cunningham

Oh yes and tl means today's low. Th means today's high and wc means week's
close.

Bill
 
F

Fred

    I have create these 2 files. Called main.c and atr.c. They seem to work
pretty well. I just wanted to submit them to see what if any errors others
that know more might find. Thanks.

atr.c

#include <stdio.h>

double
atr (double th, double tl, double wc)
{
  if (th - tl > th - wc && tl - wc < th - tl)
    {
      return th - tl;
    }
  if (th - wc > th - tl && tl - wc < th - wc)
    {
      return th - wc;
    }
  if (tl - wc > th - wc && th - tl < tl - wc)
    {
      return tl - wc;
    }

}

main.c

#include <stdio.h>
#include <stdlib.h>

extern double atr ( double th, double tl, double wc );

int
main (int argc, char *argv[])
{
  if (argc != 4)
    {
      fprintf (stderr, "usage error th, tl, wc\n");
      exit (EXIT_FAILURE);
    }
  double th, tl, wc;
  th = strtod (argv[1], NULL);
  tl = strtod (argv[2], NULL);
  wc = strtod (argv[3], NULL);
  printf("%.2f\n", atr(th, tl, wc));

}

You haven't said what the intent of the atr function is, so how are
we to know whether it is getting the right answer?

Just a bit of math shows that there are cleaner comparisons.
For example,

if ( th - tl > th - wc )
is the same as
if ( wc > tl )
 
U

user923005

    I have create these 2 files. Called main.c and atr.c. They seem to work
pretty well. I just wanted to submit them to see what if any errors others
that know more might find. Thanks.

atr.c

#include <stdio.h>

double
atr (double th, double tl, double wc)
{
  if (th - tl > th - wc && tl - wc < th - tl)
    {
      return th - tl;
    }
  if (th - wc > th - tl && tl - wc < th - wc)
    {
      return th - wc;
    }
  if (tl - wc > th - wc && th - tl < tl - wc)
    {
      return tl - wc;
    }

}

main.c

#include <stdio.h>
#include <stdlib.h>

extern double atr ( double th, double tl, double wc );

int
main (int argc, char *argv[])
{
  if (argc != 4)
    {
      fprintf (stderr, "usage error th, tl, wc\n");
      exit (EXIT_FAILURE);
    }
  double th, tl, wc;
  th = strtod (argv[1], NULL);
  tl = strtod (argv[2], NULL);
  wc = strtod (argv[3], NULL);
  printf("%.2f\n", atr(th, tl, wc));

}

Having fixed some of the more obvious errors, I would try this one:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

static double atr(double th, double tl, double wc)
{
if (th - tl > th - wc && tl - wc < th - tl) {
return th - tl;
}
if (th - wc > th - tl && tl - wc < th - wc) {
return th - wc;
}
if (tl - wc > th - wc && th - tl < tl - wc) {
return tl - wc;
}
assert(0);
return sqrt(-1.);
}


int main(int argc, char *argv[])
{
double th,
tl,
wc;
if (argc != 4) {
fprintf(stderr, "usage error th, tl, wc\n");
exit(EXIT_FAILURE);
}
th = strtod(argv[1], NULL);
tl = strtod(argv[2], NULL);
wc = strtod(argv[3], NULL);
printf("%.2f\n", atr(th, tl, wc));
return 0;
}

But then give it inputs of 20 20 20 and see what happens.
 
W

Walter Roberson

Fred said:
Just a bit of math shows that there are cleaner comparisons.
For example,
if ( th - tl > th - wc )
is the same as
if ( wc > tl )

Alegebraically the same, but not the same in the domain of
binary floating point numbers... especially if th is a NaN.
 
B

Bill Cunningham

Having fixed some of the more obvious errors, I would try this one:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

static double atr(double th, double tl, double wc)
{
if (th - tl > th - wc && tl - wc < th - tl) {
return th - tl;
}
if (th - wc > th - tl && tl - wc < th - wc) {
return th - wc;
}
if (tl - wc > th - wc && th - tl < tl - wc) {
return tl - wc;
}
assert(0);
return sqrt(-1.);
}

Assert. Hum never used it. I'll check it out.

Bill
 
B

Bill Cunningham

You haven't said what the intent of the atr functio
n is, so how are
we to know whether it is getting the right answer?

Ceck my second post. Any answer that is a postive number might be right.

Just a bit of math shows that there are cleaner comparisons.
For example,

if ( th - tl > th - wc )
is the same as
if ( wc > tl )
 
B

Bill Cunningham

[snip]

assert(0);
return sqrt(-1.);
}

What's the sqrt function called for ? And the 0 passed to assert?

Bill
 
K

Keith Thompson

Bill Cunningham said:
Having fixed some of the more obvious errors, I would try this one:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

static double atr(double th, double tl, double wc)
{
if (th - tl > th - wc && tl - wc < th - tl) {
return th - tl;
}
if (th - wc > th - tl && tl - wc < th - wc) {
return th - wc;
}
if (tl - wc > th - wc && th - tl < tl - wc) {
return tl - wc;
}
assert(0);
return sqrt(-1.);
}

Assert. Hum never used it. I'll check it out.

Bill

In your last few messages, quoted text is not marked. In the above,
the text starting with "Having fixed some ..." plus the C code is
quoted from user923005's previous article; only the last line,
starting "Assert. Hum ..." is new.

Whatever you're doing differently when posting followups, please go
back to what you were doing before.
 
B

Bill Cunningham

Having fixed some of the more obvious errors, I would try this one:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

static double atr(double th, double tl, double wc)
{
if (th - tl > th - wc && tl - wc < th - tl) {
return th - tl;
}
if (th - wc > th - tl && tl - wc < th - wc) {
return th - wc;
}
if (tl - wc > th - wc && th - tl < tl - wc) {
return tl - wc;
}
assert(0);
return sqrt(-1.);
}


int main(int argc, char *argv[])
{
double th,
tl,
wc;
if (argc != 4) {
fprintf(stderr, "usage error th, tl, wc\n");
exit(EXIT_FAILURE);
}
th = strtod(argv[1], NULL);
tl = strtod(argv[2], NULL);
wc = strtod(argv[3], NULL);
printf("%.2f\n", atr(th, tl, wc));
return 0;
}

But then give it inputs of 20 20 20 and see what happens.

After running this program several times now I am discovering that I am
getting negative numbers. I should never get negative numbers here.

Bill
 
B

Bill Cunningham

After running this program several times now I am discovering that I am
getting negative numbers. I should never get negative numbers here.

Bill

Sorry not your program to clarify I mean mine. No misunderstanding.

Bill
 
D

Default User

Keith said:
In your last few messages, quoted text is not marked. In the above,
the text starting with "Having fixed some ..." plus the C code is
quoted from user923005's previous article; only the last line,
starting "Assert. Hum ..." is new.

Whatever you're doing differently when posting followups, please go
back to what you were doing before.


Probably Bill is using Outlook Express (I have him killfiled, so I
can't check), and is running into the incompatibility with Google
Groups, which Mr. Corbit is using. If so, that can be fixed either by
switching newsreaders (recommended) or downloading and installing OE
Quotefix.




Brian
 
B

Ben Bacarisse

Bill Cunningham said:
You haven't said what the intent of the atr function is, so how are
we to know whether it is getting the right answer?

According to that document, what you are trying to calculate with the
atr function is called the "true range". The average true range is
the (moving) average of this value. I think the function is
mis-named -- you shoul call it 'tr' or, better, 'true_range'.

Let me recap your version:

double
atr (double th, double tl, double wc)
{
if (th - tl > th - wc && tl - wc < th - tl)
{
return th - tl;
}
if (th - wc > th - tl && tl - wc < th - wc)
{
return th - wc;
}
if (tl - wc > th - wc && th - tl < tl - wc)
{
return tl - wc;
}
}

Part of the art of programming is to write programs that are clear
rather than just correct. I would write this:

double max_of_3(double a, double b, double c)
{
return fmax(fmax(a, b), c);
}

double true_range(double th, double tl, double wc)
{
return max_of_3(th - tl, th - wc, tl - wc);
}

This makes the intent much clearer. Yours is much less clear. In
fact it has a subtle problem that is not easy to reason about. As a
hint, are you sure that at least one of the three big conditions is
always true?
 
B

Ben Bacarisse

Bill Cunningham said:
Oh yes and tl means today's low. Th means today's high and wc means week's
close.

If you feel the urge to write this, then it suggests that the
parameters should be called todays_low, todays_high and weeks_close.
 
A

Antoninus Twink

On 11 Jun 2008 at 20:43, Default User wrote:
[snip crap]

Marvelous. Just when you thought it was safe, the Loser has crawled back
out from under his stone. I suppose that means we have to endure his
bitching about top-posting, topicality and "trolls" again, as well as
the continual updates on the latest contents of his killfile (as if
anyone gives a damn).
 
B

Bill Cunningham

According to that document, what you are trying to calculate with the
atr function is called the "true range". The average true range is
the (moving) average of this value. I think the function [snip]

Part of the art of programming is to write programs that are clear
rather than just correct. I would write this:

double max_of_3(double a, double b, double c)
{
return fmax(fmax(a, b), c);
}

I don't quite get the fmax(fmax(a,b),c);
I know it's algebraic.
 
U

user923005

According to that document, what you are trying to calculate with the
atr function is called the "true range".  The average true range is
the (moving) average of this value.  I think the function
[snip]

Part of the art of programming is to write programs that are clear
rather than just correct.  I would write this:
double max_of_3(double a, double b, double c)
{
    return fmax(fmax(a, b), c);
}

    I don't quite get the fmax(fmax(a,b),c);
I know it's algebraic.


double true_range(double th, double tl, double wc)
{
   return max_of_3(th - tl, th - wc, tl - wc);
}
This makes the intent much clearer.  Yours is much less clear.  In
fact it has a subtle problem that is not easy to reason about.  As a
hint, are you sure that at least one of the three big conditions is
always true?

/*
The true range is the greatest of the following:
1) The difference between the current high and the current low
2) The difference between the current high and the previous close
3) The difference between the current low and the previous close
*/
#include <math.h>
double true_range(double current_high, double current_low,
double previous_close)
{
double d1 = fabs(current_high - current_low);
double d2 = fabs(current_high - previous_close);
double d3 = fabs(current_low - previous_close);
double dmax = d1 > d2 ? d1 : d2;
dmax = dmax > d3 ? dmax : d3;
return dmax;
}

#ifdef UNIT_TEST
#include <stdio.h>
int main(void)
{
double current_high = 0;
double current_low = 0;
double previous_close = 0;
char string[256] = {0};
int converted;
oops0:
puts("Enter current high value:");
fflush(stdout);
if (fgets(string, sizeof string, stdin)) {
converted = sscanf(string, "%lf", &current_high);
if (converted != 1)
goto oops0;
oops1:
puts("Enter current low value:");
fflush(stdout);
if (fgets(string, sizeof string, stdin)) {
converted = sscanf(string, "%lf", &current_low);
if (converted != 1)
goto oops1;
oops2:
puts("Enter previous close value:");
fflush(stdout);
if (fgets(string, sizeof string, stdin)) {
converted = sscanf(string, "%lf", &previous_close);
if (converted != 1)
goto oops2;
printf("true range of (%f, %f, %f) is %f\n",
current_high,
current_low,
previous_close,
true_range(current_high, current_low,
previous_close)
);

} else {
goto oops2;
}
} else {
goto oops1;
}
} else {
goto oops0;
}

return 0;
}
/* E.g.:
Enter current high value:
111
Enter current low value:
123
Enter previous close value:
125
true range of (111.000000, 123.000000, 125.000000) is 14.000000
*/
#endif
 
N

Nick Keighley

    I have create these 2 files. Called main.c and atr.c. They seem to work
pretty well. I just wanted to submit them to see what if any errors others
that know more might find. Thanks.

atr.c

#include <stdio.h>

not needed
double
atr (double th, double tl, double wc)

a comment would be nice. I've no idea if this is correct
because I don't know what it's supposed to do.
If Average True Range is a well known calculation
you could make a reference to a stats book or whatever.

{
  if (th - tl > th - wc && tl - wc < th - tl)
    {
      return th - tl;
    }
  if (th - wc > th - tl && tl - wc < th - wc)
    {
      return th - wc;
    }
  if (tl - wc > th - wc && th - tl < tl - wc)
    {
      return tl - wc;
    }

}

ah! sane layout. Good.


main.c

#include <stdio.h>
#include <stdlib.h>

extern double atr ( double th, double tl, double wc );

I must admit I'd put this in a header file.
It makes no odds with a single function but as you get
more and more c files and more and more functions it is easier
to manage header files.

int
main (int argc, char *argv[])
{
  if (argc != 4)
    {
      fprintf (stderr, "usage error th, tl, wc\n");
      exit (EXIT_FAILURE);
    }
  double th, tl, wc;

this is invalid in C89
  th = strtod (argv[1], NULL);

no error checking on strtod()

  tl = strtod (argv[2], NULL);
  wc = strtod (argv[3], NULL);
  printf("%.2f\n", atr(th, tl, wc));

main() should return a value (eg. EXIT_SUCCESS)


--
Nick Keighley

"Object-oriented programming is an exceptionally bad idea
that could only have originated in California."
Dijkstra
 
U

user923005

According to that document, what you are trying to calculate with the
atr function is called the "true range".  The average true range is
the (moving) average of this value.  I think the function
Part of the art of programming is to write programs that are clear
rather than just correct.  I would write this:
double max_of_3(double a, double b, double c)
{
    return fmax(fmax(a, b), c);
}
    I don't quite get the fmax(fmax(a,b),c);
I know it's algebraic.

/*
The true range is the greatest of the following:
 1) The difference between the current high and the current low
 2) The difference between the current high and the previous close
 3) The difference between the current low and the previous close
*/
#include <math.h>
double          true_range(double current_high, double current_low,
double previous_close)
{
    double          d1 = fabs(current_high - current_low);
    double          d2 = fabs(current_high - previous_close);
    double          d3 = fabs(current_low - previous_close);
    double          dmax = d1 > d2 ? d1 : d2;
    dmax = dmax > d3 ? dmax : d3;
    return dmax;

}

#ifdef UNIT_TEST
#include <stdio.h>
int             main(void)
{
    double          current_high = 0;
    double          current_low = 0;
    double          previous_close = 0;
    char            string[256] = {0};
    int             converted;
oops0:
    puts("Enter current high value:");
    fflush(stdout);
    if (fgets(string, sizeof string, stdin)) {
        converted = sscanf(string, "%lf", &current_high);
        if (converted != 1)
            goto oops0;
oops1:
        puts("Enter current low value:");
        fflush(stdout);
        if (fgets(string, sizeof string, stdin)) {
            converted = sscanf(string, "%lf", &current_low);
            if (converted != 1)
                goto oops1;
    oops2:
            puts("Enter previous close value:");
            fflush(stdout);
            if (fgets(string, sizeof string, stdin)) {
                converted = sscanf(string, "%lf", &previous_close);
                if (converted != 1)
                    goto oops2;
                printf("true range of (%f, %f, %f) is %f\n",
                       current_high,
                       current_low,
                       previous_close,
                       true_range(current_high, current_low,
previous_close)
                    );

            } else {
                goto oops2;
            }
        } else {
            goto oops1;
        }
    } else {
        goto oops0;
    }

    return 0;}

/* E.g.:
Enter current high value:
111
Enter current low value:
123
Enter previous close value:
125
true range of (111.000000, 123.000000, 125.000000) is 14.000000
*/
#endif

Here is the other half of the problem:

#include <assert.h>

typedef struct accumulator {
double sum;
long prior;
long later;
} accumulator;

/*
This function takes a vector node v[k] and computes a sliding window
average for the point at v[k].
*/
double window(const double *const v, accumulator a)
{
long i;
a.sum = 0;
// Add in previous values
for (i = -a.prior; i < 0; i++)
a.sum += v;
// Add in current value
a.sum += v[0];
// Add in subsequent values
for (i = 1; i <= a.later; i++)
a.sum += v;

return a.sum / (a.prior + a.later + 1);
}

/*
This is a sliding window moving average.
We can use historic data windows or future data windows or windows
that use both prior and later values.

double *vector : raw input vector consisting of vector_length
double values.
double *smoothed_vector : smoothed output vector consisting of
vector_length double values.
long period : number of items to combine as the average
(e.g. weekly = 7)
long vector_length : length of both the input and output vectors
*/
void moving_average(const double *const vector, double
*smoothed_vector, long prior, long later, const long vector_length)
{
accumulator a = {0};
long i;

assert(prior >= 0);
assert(later >= 0);
assert(vector_length >= 0);
assert(vector);
assert(smoothed_vector);
prior = prior < vector_length ? prior : vector_length;
later = later < vector_length ? later : vector_length;
for (i = 0; i < vector_length; i++) {
a.prior = prior > i ? i : prior;
a.later = later > vector_length - i ? vector_length - i :
later;
smoothed_vector = window(&vector, a);
}
}

#ifdef UNIT_TEST
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <time.h>

double raw_vector[20];
double smoothed_vector[20];
void show_vector(double *v, size_t len)
{
size_t index;
for (index = 0; index < len; index++)
printf("%*.*g\n ", DBL_DIG + 3, DBL_DIG, v[index]);
}
int main(void)
{
double factor = 1.0 / RAND_MAX;
size_t rvlen = sizeof raw_vector / sizeof raw_vector[0];
size_t svlen = sizeof smoothed_vector / sizeof
smoothed_vector[0];
size_t i;

assert(rvlen == svlen);
srand(time(NULL));
raw_vector[0] = rand() * factor;
for (i = 1; i < rvlen; i++) {
raw_vector = raw_vector[i - 1] + (rand() * (rand() % 2 ?
factor : -factor));
}
puts("Raw vector:");
show_vector(raw_vector, rvlen);

moving_average(raw_vector, smoothed_vector, 0, 7, rvlen);
puts("\nSmoothed vector [0,7]:");
show_vector(smoothed_vector, rvlen);

moving_average(raw_vector, smoothed_vector, 7, 0, rvlen);
puts("\nSmoothed vector [7,0]:");
show_vector(smoothed_vector, rvlen);

moving_average(raw_vector, smoothed_vector, 7, 7, rvlen);
puts("\nSmoothed vector [7,7]:");
show_vector(smoothed_vector, rvlen);

return 0;
}
#endif
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top