# Copyright 2007, 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/>.
package App::Chart::Series::Derived::TDREI;
use 5.010;
use strict;
use warnings;
use Carp;
use List::Util qw(min max);
use Locale::TextDomain ('App-Chart');
use base 'App::Chart::Series::Indicator';
use App::Chart::Series::Calculation;
use App::Chart::Series::Derived::WilliamsR;
# http://ta-glossary.netfirms.com/taglossary-R.htm
# Description quoting Tom DeMark on the calculation, sample BDY from
# 2004.
#
# http://www.linnsoft.com/tour/techind/tdrei.htm
# Formula, shows both num and den terms both zeroed by condition.
# Sample on AOL call options.
#
# http://www.prophet.net/analyze/popglossary.jsp?studyid=TD_REI
# Description, sample of Sunoco Inc (NYSE symbol SUN), year not shown
# but is Jan/Feb 2003. Note 6-day sums for the sample, not 5.
#
# http://trader.online.pl/MSZ/e-w-DeMark_Range_Expansion_Index.html
# Formula (parens in denominator look misplaced though). TD3 and TD4
# work as an "or" of those two conditions.
# http://trader.online.pl/MSZ/e-w-DeMark_Range_Expansion_Index_II.html
# Formula, similar but using momentum func, sample on WIG20.
#
# http://secure.aspenres.com/Documents/help/userguide/help/dmrkhelp/demarkRange_Expansion_Index.html
# Description, sample of CME S&P 500 futures SPU05.CME.
#
# http://www.traders.com/documentation/feedbk_docs/archive/0897/Abstracts_new/DeMark/DEMARK9708.html
# http://store.traders.com/-v15-c08-thetdra-pdf.html
# Intro to Tom DeMark "The TD Range Expansion Index (TD REI)" TASC 15:8
# August 1997 (rest for sale), revising original from his book "The New
# Science of Technical Analysis".
#
# http://www.meta-formula.com/Metastock-Formulas-T.html
# Formula.
#
# http://www.amibroker.com/library/formula.php?id=15
# Formula, showing only numerator suppressed by condition.
#
# http://www.aiqsystems.com/PriceandVolumeBasedStrategies1.htm#down17
# Code.
# http://www.aiqsystems.com/TDREI.gif
# Sample of Cabot Corp (NYSE symbol CBT) from Jan to Jun 2002. Period
# not shown, looks like 5 days.
#
sub longname { __('TD REI - Range Expansion Index') }
sub shortname { __('TDREI') }
sub manual { __p('manual-node','TD Range Expansion Index') }
use constant
{ hlines => [ -40, 45 ],
type => 'indicator',
units => 'percentage_plus_or_minus_100',
minimum => -100,
maximum => 100,
parameter_info => [ { name => __('Stddev Days'),
key => 'tdrei_days',
type => 'integer',
minimum => 1,
default => 5 }],
};
sub new {
my ($class, $parent, $N) = @_;
$N //= parameter_info()->[0]->{'default'};
($N > 0) || croak "TDREI bad N: $N";
return $class->SUPER::new
(parent => $parent,
parameters => [ $N ],
arrays => { values => [] },
array_aliases => { });
}
*fill_part = \&App::Chart::Series::Derived::WilliamsR::fill_part;
# the first value goes into the sum at the 9th call, it's the first of
# $N-1 wanted for the sums, hence 8+$N-1
sub warmup_count {
my ($class_or_self, $N) = @_;
return $N + 7;
}
# Return a procedure which calculates a relative volatility index, using
# Dorsey's original 1993 definition, over an accumulated window.
#
sub proc {
my ($class_or_self, $N) = @_;
my $sumval_proc = App::Chart::Series::Calculation->sum($N);
my $sumabs_proc = App::Chart::Series::Calculation->sum($N);
my (@C, @H, @L);
return sub {
my ($high, $low, $close) = @_;
$high //= $close;
$low //= $close;
unshift @C, $close;
unshift @H, $high;
unshift @L, $low;
if (@C > 9) {
pop @C;
pop @H;
pop @L;
}
my $tdrei;
if (@C >= 9) {
my $h2 = $H[2];
my $l2 = $L[2];
my $use = (($h2 >= $C[7]
|| $h2 >= $C[8]
|| $high >= $L[5]
|| $high >= $L[6])
&& ($l2 <= $C[7]
|| $l2 <= $C[8]
|| $low <= $H[5]
|| $low <= $H[6]));
my $val = ($use ? ($high - $h2) + ($low - $l2) : 0);
my $absval = abs($high-$h2) + abs($low-$l2);
my $sumval = $sumval_proc->($val);
my $sumabs = $sumabs_proc->($absval);
$tdrei = ($sumabs == 0 ? 0 : 100 * $sumval / $sumabs);
}
return $tdrei;
};
}
1;
__END__
# =head1 NAME
#
# App::Chart::Series::Derived::TDREI -- Tom DeMark range expansion index
#
# =head1 SYNOPSIS
#
# my $series = $parent->TDREI($N);
#
# =head1 DESCRIPTION
#
# ...
#
# =head1 SEE ALSO
#
# L<App::Chart::Series>
#
# =cut