The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

# Copyright 2008, 2009, 2010 Kevin Ryde

# This file is part of Chart.
#
# Chart is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3, or (at your option) any later version.
#
# Chart is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with Chart.  If not, see <http://www.gnu.org/licenses/>.

use strict;
use warnings;
use Test::More tests => 52;

use lib 't';
use MyTestHelpers;
BEGIN { MyTestHelpers::nowarnings() }

require App::Chart::Series::Derived::DEMA;

#-----------------------------------------------------------------------------
# dema_omitted()

# return the coefficient of the f^k term in an EMA
sub ref_ema_coef {
  my ($f, $k) = @_;
  return 1 - $f;
}
# return the coefficient of the f^k term in an EMAofEMA
sub ref_ema2_coef {
  my ($f, $k) = @_;
  return (1 - $f) * (1 - $f) * ($k + 1);
}
# return the coefficient of the f^k term in a DEMA
sub ref_dema_coef {
  my ($f, $k) = @_;
  return 2*ref_ema_coef($f,$k) - ref_ema2_coef($f,$k);
}

sub ref_dema_total_abs_weight {
  my ($N, $f) = @_;
  return 1 + 2 * $f**($N+1);
}

sub ref_dema_omitted {
  my ($N, $f, $k) = @_;
  my $total = 0;
  my $terms = 0;

  for (;;) {
    $terms++;
    $k++;
    my $weight = abs($f**$k * ref_dema_coef($f,$k));
    if ($terms >= $N*5 && $weight/$total < 0.0000001) {
      last;
    }
    $total += $weight;
  }
  return $total / ref_dema_total_abs_weight($N,$f);
}

sub nearly_eq {
  my ($ref, $got) = @_;
  my $ret = (abs($ref-$got) <= 0.01);
  if (! $ret) {
    diag "ref=$ref got=$got";
  }
  return $ret;
}

{
  my $N = 10;
  require App::Chart::Series::Derived::EMA;
  my $f = App::Chart::Series::Derived::EMA::N_to_f ($N);
  foreach my $k (1 .. 50) {
    # diag "$N $f $k";
    my $ref = ref_dema_omitted ($N, $f, $k);
    my $got = App::Chart::Series::Derived::DEMA::dema_omitted ($N, $f, $k);
    ok (nearly_eq ($ref, $got),
        "ema2_omitted $k  (got=$got)");
  }
}

#-----------------------------------------------------------------------------
# warmup_count()

{ my $N = 1;
  is (App::Chart::Series::Derived::DEMA->warmup_count($N),
      0,
      "warmup_count($N)");
}

{ my $N = 2;
  my $got = App::Chart::Series::Derived::DEMA->warmup_count($N);
  ok ($got > 0,
      "warmup_count($N) got=$got");
}

exit 0;