[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;
}