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

[GT] alias resolution ... sub resolve_alias revisited



aloha gt'ers

i've hacked up a replacement resolve_alias subroutine for evaluation.
the entire sub is provided so you can hack it in for eval by renaming
the current version something else.

what does it do you're thinking. well, it gives you a helpful error message
when it doesn't find the alias, or it gives you complete feedback if
any parameter is missing.

examples are better than my ramblings:

with these aliases in your .gt/options file:
aliases::global::mysma[]            	SY:SMA | TF:AcceptAll | CS:Stop:Fixed #1
aliases::global::tfs[]              	SY:TFS #1 #2 | CS:SY:TFS #1 | CS:Stop:Fixed #3
aliases::global::tts                	TTS
aliases::global::tts[]              	SY:TTS #1 #2 | CS:Stop:ExtremePrices #2 #3 | TF:OneTrade
aliases::global::ttsx               	TTS[20,10,1]
aliases::global::rw_sys4[]          	SY:Generic S:Generic:And { S:Generic:Above { I:Generic:Eval int( { I:Generic:PeriodAgo 1 { I:Prices VOLUME } } * #1 ) } { I:Generic:Eval int( { I:Generic:PeriodAgo 2 { I:Prices VOLUME } } * #2 ) } } { S:Generic:Above { I:Generic:Eval int( { I:Generic:PeriodAgo 1 { I:Prices CLOSE } } * #3 ) } { I:Generic:Eval int( { I:Generic:PeriodAgo 2 { I:Prices CLOSE } } * #4 ) } } | OF:ClosedToClose | TF:LongOnly | CS:Stop::KeepRunUp | MM:FixedShares

if you do %    backtest.pl 'rw_sys4[20,30]' GOOG
backtest.pl: error: alias 'rw_sys4[20,30]' is missing parameters #3 #4.
The alias expands to
"SY:Generic S:Generic:And { S:Generic:Above { I:Generic:Eval int( { I:Generic:PeriodAgo 1 { I:Prices VOLUME } } * 20 ) } { I:Generic:Eval int( { I:Generic:PeriodAgo 2 { I:Prices VOLUME } } * 30 ) } } { S:Generic:Above { I:Generic:Eval int( { I:Generic:PeriodAgo 1 { I:Prices CLOSE } } * #3 ) } { I:Generic:Eval int( { I:Generic:PeriodAgo 2 { I:Prices CLOSE } } * #4 ) } } | OF:ClosedToClose | TF:LongOnly | CS:Stop::KeepRunUp | MM:FixedShares"

or if you try %    backtest.pl mysma GOOG
backtest.pl: error: alias key "Aliases::Global::mysma" was not found.
However, `mysma[]' was. It expects 1 parameter, try 'mysma[#1]'
That alias expands to
"SY:SMA | TF:AcceptAll | CS:Stop:Fixed #1"

an alias without params like ttsx now works as 'ttsx[]'
%     backtest.pl 'ttsx[]' GOOG
## Analysis of SY:TTS
...

but if you throw in a param it fails, but helpfully: %     backtest.pl 'ttsx[45]' GOOG
backtest.pl: error: alias key "Aliases::Global::ttsx" was not found.
ah ha! Alias `ttsx[45]' doesn't expect any parameters, try 'ttsx'
That alias expands to
"TTS[20,10,1]"

and if you really mis-tpye things  %    backtest.pl myema  GOOG
backtest.pl: error: alias key "Aliases::Global::myema" was not found.
just like before, but you will not be staring at your list of aliases
and seeing Aliases::Global::myema[] but not knowing why it's not being found.


even with these improvements it still fails if you have defined recursive
aliases like tts and tts[] in the examples list above.
%      backtest.pl tts  GOOG
Deep recursion on subroutine "GT::Tools::resolve_alias" at ../GT/Tools.pm line 252.

i haven't found a solution for that yet.

oh yea! almost forgot. extra whitespace in the param list will not cause
problems. so things like 'mysma[   20  ]', 'tts[ 30   ,   40, 50   ]' work now.

finally i've not incorporated the alternate while ($sysname !~ /\|/) regex
as i've yet to find a condition where it helps. of course the amount of testing
i've conducted is very limited and certainly simplistic. however, i'd argue that
gt identifiers (e.g. indicator, signal and system component specifications) are
case sensitive and have been so forever, so the pattern /i modifier is likely
incorrect.


feedback is welcome

ras

replacement subroutine -- rename existing one and drop in this one
oh yea! filename might be extremely helpful: GT/Tools.pm
sub resolve_alias {
   my ($alias) = @_;
   my $name = $alias;
   my @param = ();
   my $sysname = '';
   my $msg = '';

   if ($alias =~ m/^\s*(.*)\s*\[(.*)\]\s*$/) {
       $name = $1;
       ( $_ = $2 ) =~ tr/[ \t]//d;
       @param = split /,/;
   }
# remove "Aliases::Global::" in any case, just in case
   $name =~ s/aliases:+global:+//ig;

   if (scalar @param) {
       if ( $sysname = GT::Conf::get("Aliases::Global::$name" . "[]") ) {
           # $sysname is valid
       } else {

           $msg = "alias key \"Aliases::Global::$name\""
            . " was not found.\n";

          if ( $sysname = GT::Conf::get("Aliases::Global::$name") ) {
              $msg .= "ah ha! Alias `$alias' doesn't expect any parameters, "
               . "try '$name'\n";
              $sysname =~ s
AT
\|@\n| @g;
              $msg .=  "That alias expands to\n\"$sysname\"\n";
          }
       ( my $prog_name = $0 ) =~ s
AT
^.*/@@;    # lets identify ourself
       die "$prog_name: error: " . "$msg";
       }

   } else {
       if ( $sysname = GT::Conf::get("Aliases::Global::$name") ) {
           # $sysname is valid
       } else {

           $msg = "alias key \"Aliases::Global::$name\""
            . " was not found.\n";

           if ( $sysname = GT::Conf::get("Aliases::Global::$name" . "[]") ) {
               my @param = $sysname =~ m/#(\d+)/g;

               my $param_count = 0;
               foreach ( @param ) {
                   $param_count = max( $_, $param_count );
               }

               my $plural = "";
               $plural = "s" if ( $param_count > 1 );
               $alias =~ s/\[\]//;
               $msg .= "However, `$alias\[\]' was. "
                . "It expects $param_count parameter$plural,";
               if ( $param_count == 1 ) {
                   $msg .= " try '$name" . "[#1]'\n";
               } elsif ( $param_count == 2 ) {
                   $msg .= " try '$name" . "[#1, #2]'\n";
               } elsif ( $param_count == 3 ) {
                   $msg .= " try '$name" . "[#1, #2, #3]'\n";
               } else {
                   $msg .= " try '$name" . "[#1, #2, .. #$param_count]'\n";
               }
               $sysname =~ s
AT
\|@\n| @g;
               $msg .= "That alias expands to\n\"$sysname\"\n";
             }
        ( my $prog_name = $0 ) =~ s
AT
^.*/@@;    # lets identify ourself
        die "$prog_name: error: " . "$msg";
        }

   }

   # The alias content may list another alias ...
   while ($sysname !~ /\|/) {
   #while ($sysname !~ /^(I|Indicators|S|Signals|SY|Systems|CS|CloseStrategy|
   #                    MM|MoneyManagement|TF|TradeFilters|OF|OrderFactory|
   #                    A|Analyzers|PE|PortfolioEvaluation)/i) {
   #while ($sysname !~ /^(I|SY|S|CS|MM|TF|OF|A|PE)|
   #                   ^(Indicators|Signals|Systems|CloseStrategy|
   #                   MoneyManagement|TradeFilters|OrderFactory|Analyzers|
   #                   PortfolioEvaluation)/i) {
       $sysname = resolve_alias($sysname);
   }
   my $n = 1;
   foreach (@param)
   {
       $sysname =~ s/#$n/$_/g;
       $n++;
   }

   # Take care about operators + - / * in a string like #1+#2
   eval {
       $sysname =~ s|(\d+)\*(\d+)| $1 * $2 |eg;
       $sysname =~ s|(\d+)\/(\d+)| $1 / $2 |eg;
       $sysname =~ s|(\d+)\+(\d+)| $1 + $2 |eg;
       $sysname =~ s|(\d+)\-(\d+)| $1 - $2 |eg;
   };
# if ($sysname =~ /#(\d+)/)
   if ( my @missing_params = $sysname =~ /(#\d+)/g )
   {
       my $msg = '';
       if ( $#missing_params == 0 ) {
           $msg = "alias '$alias' is missing parameter @missing_params.\n";
       } else {
           $msg = "alias '$alias' is missing parameters @missing_params.\n";
       }
       $sysname =~ s
AT
\|@\n| @g;
       $msg .= "The alias expands to\n\"$sysname\"\n";
       ( my $prog_name = $0 ) =~ s
AT
^.*/@@;    # lets identify ourself
       die "$prog_name: error: " . "$msg";
   }
   return $sysname;
}