[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GT] Bug in FromTimeframe Indicator



The FromTimeframe indicator uses an internal cache where it stores values.
The problem i came across is that a GT::Indicator object can be
created once, but used many times for different symbols.
The attached gt_bugdemo.pl illustrates this problem.
The code creates a GT::Indicator::FromTimeframe object and then
calculates the value of the indicator.
However, because of the internal cache mentioned earlier, the result
of the indicator will always be the same as the first calculated
symbol.

As far as I can tell GT's Scripts don't use the indicator in this way,
but this could be a problem for someone using GT as a library to write
trading applications.

The attached patch overcomes this issue.

To reproduce this issue:

Run the attached gt_bugdemo.pl, the output of the script should be the
same for all symbols it calculates.  This value is only correct for
the first calculated symbol.
Apply the attached patch
Run bug_demo.pl once again.  The output will have print different and
correct indicator values for each symbol.

Attachment: gt_bugdemo.pl
Description: Perl program

Index: GT/Indicators/FromTimeframe.pm
===================================================================
--- GT/Indicators/FromTimeframe.pm	(revision 647)
+++ GT/Indicators/FromTimeframe.pm	(working copy)
@@ -17,7 +17,7 @@
 use GT::Tools qw(extract_object_number);
 
 @ISA = qw(GT::Indicators);
-
AT
NAMES = ("Prices[#*]");
+
AT
NAMES = ("FromTimeframe[#*]");
 @DEFAULT_ARGS = ("{I:Prices CLOSE}", "week", 0);
 
 =head1 NAME
@@ -54,35 +54,37 @@
 
 sub calculate {
     my ($self, $calc, $i) = @_;
+    my $code = $calc->{'code'};
     my $indic = $calc->indicators;
     my $nb = $self->{'args'}->get_arg_values($calc, $i, 3);
 
     # Initialize
-    if (!defined($self->{'special_calc'})) {
-        $self->{'special_tf'} = GT::DateTime::name_to_timeframe($self->{'args'}->get_arg_constant(2));
-        $self->{'special_prices'} = $calc->prices->convert_to_timeframe($self->{'special_tf'});
-        $self->{'special_calc'} = GT::Calculator->new($self->{'special_prices'});
-	$self->{'special_calc'}->set_code($calc->code());
+    if (!defined($self->{$code}->{'special_calc'})) {
+        $self->{$code}->{'special_tf'} = GT::DateTime::name_to_timeframe($self->{'args'}->get_arg_constant(2));
+        $self->{$code}->{'special_prices'} = $calc->prices->convert_to_timeframe($self->{$code}->{'special_tf'});
+        $self->{$code}->{'special_calc'} = GT::Calculator->new($self->{$code}->{'special_prices'});
+	$self->{$code}->{'special_calc'}->set_code($calc->code());
+    } else {
     }
 
 
     my $date = $calc->prices->at($i)->[$DATE];
     my $time = GT::DateTime::map_date_to_time($calc->prices->timeframe(), $date);
-    $date = GT::DateTime::map_time_to_date($self->{'special_tf'}, $time);
+    $date = GT::DateTime::map_time_to_date($self->{$code}->{'special_tf'}, $time);
 
-    if ($self->{'special_prices'}->has_date($date)) {
-        my $j = $self->{'special_prices'}->date($date);
+    if ($self->{$code}->{'special_prices'}->has_date($date)) {
+        my $j = $self->{$code}->{'special_prices'}->date($date);
         my $tmp = $self->{'args'}->get_arg_names(1);
         $tmp =~ s/^{|}$//g;
 
         my $args = GT::ArgsTree->new( $tmp );
         my $name_index = extract_object_number($args->get_arg_names(1));
 	    my $ob = $self->{'args'}->get_arg_object(1);
-	    $ob->calculate($self->{'special_calc'}, $j - $nb);
-	    my $res = $self->{'special_calc'}->indicators->get($ob->get_name($name_index), $j - $nb);
+	    $ob->calculate($self->{$code}->{'special_calc'}, $j - $nb);
+	    my $res = $self->{$code}->{'special_calc'}->indicators->get($ob->get_name($name_index), $j - $nb);
         $indic->set($self->get_name, $i, $res);
     }
 
 }
 
-1;
\ No newline at end of file
+1;