## eiffel-mas-tips

 [MAS-tips] Re: [MAS-discuss] Building indicators From: Jim Cochrane - 2003-05-26 05:07:34 ```Hi Paul. > Jim, > > I'm hoping you may be able to point me in the right direction. What I am > trying to build is an indicator ( I think its an indicator rather than > an analyser/generator ). The spec is:- > > Objective - to detect the point at which the MACD Histogram changes > direction. > > The direction of the histogram for the 3 prior days must be the same ( > in other words it slopes up/down then changes direction ). > > The intention is then to build a generator which tests the point at > which the change of direction occurs ( ie against a signal line of zero > slope ). > > I seem to have the change of direction sorted - but I am having trouble > understanding the way in which to build the 3 day test. You're using a slope analyzer for the change of direction, right? For the 3-day test, for such criteria I've found it helps to put it into algorithmic form (e.g, if slopesign (f)[now] = slopesign(f)[now-1] = slopesign(f)[now-2] then ..., or something like that), then translate the algorithm into a mas indicator/command structure. Sorry I don't have time to ponder what the exact structure would be, but I think because of the 3-day check you'll want an n-record-one-variable-function with n=3 that takes the macd hist. as input. And for the if slope... algorithm itself, I think you'll want to use the "boolean-numeric-client" command (which has been renamed in the current version as numeric-conditional-command, since it can be used for if/else logic). Once you figure out what to use for its "boolean operator" (the 3-day test), you can do something like: for its true command use a constant with value 1, for the false cmd, constant with value 0. (constant has been renamed numeric-value-command in the current version.) So if the result is 1, your condition holds; combine that with the slope change criteria with the and-operator and I think you'll have what you want. (I've also found that it helps to draw the command/operator tree you will use before using mas to create the indicator - you sort of have to turn yourself into a lisp machine :-).) (I think you can do what you want with 1.6.5, but you may want to upgrade, if you haven't already, to what I just put up on sourceforge (1.6.6g), since a couple powerful operator/commands have been added. This allowed me to implement parabolic SAR, which I don't believe was possible before. I'll include the "macl script" for parabolic SAR, since it may give you some good clues on how to use the numeric-conditional-command (with apologies for the difficult to parse "script syntax").) Hope this helps. Jim > > Hope this is within bounds of the discussion group - if not tell me - I > have a thick skin !! > > Regards, > > > > ------------------------------------------------------- > This SF.net email is sponsored by: ObjectStore. > If flattening out C++ or Java code to make your application fit in a > relational database is painful, don't do it! Check out ObjectStore. > Now part of Progress Software. http://www.objectstore.net/sourceforge > _______________________________________________ > Eiffel-mas-discuss mailing list > Eiffel-mas-discuss@... > https://lists.sourceforge.net/lists/listinfo/eiffel-mas-discuss Here's the parabolic SAR script. # This macl -i script implements the Parabolic SAR formula. The formula # is fairly complex and requires the new NUMERIC_VALUED_COMMAND_WRAPPER # and COMMAND_SEQUENCE operators. Below, in comments, is a perl script # that implements the formula, which I used to test that I had gotten it # right and as a model for implementing the formula in MAS. ##!/usr/bin/perl -wn # #BEGIN { # \$long = 1; # \$short = 2; # \$prev_sar = 0; # \$prev_af = 0; # \$prev_ep = 0; # \$af_max = .1999; # \$af_increment = .02; # \$trade_state = \$long; # \$initial_af_value = .2; # \$af = \$initial_af_value; # \$sar = 0; # \$ep = 0; # \$line_count = 0; # \$succeeded = 1; #} # #END { # if (\$succeeded) { # print "SUCCEEDED\n"; # } else { # print "FAILED\n"; # } #} # #if (/^#/) { next; } #@a = split; #\$date = \$a[0]; #\$high = \$a[1]; #\$low = \$a[2]; #++\$line_count; # #if (\$line_count == 1) { # init(); # \$prev_sar = \$sar; # \$prev_af = \$af; # \$prev_ep = \$ep; # next; #} # #execute(); #report(); #\$prev_sar = \$sar; #\$prev_af = \$af; #\$prev_ep = \$ep; # #sub sar_calculation { # return (\$prev_ep - \$prev_sar) * \$prev_af + \$prev_sar; #} # #sub init { # \$sar = \$low; # \$ep = \$high; #} # #sub execute { # if (\$trade_state == \$long) { # # long block # if (change_direction (\$trade_state)) { # switch_to_short(); # \$trade_state = \$short; # } else { # # remain long # \$sar = sar_calculation(); # if (\$high > \$prev_ep) { # if (\$af < \$af_max) { # \$af = \$af + \$af_increment; # } # \$ep = \$high; # } # } # } else { # # short block # # check \$trade_state == \$short end # if (change_direction (\$trade_state)) { # switch_to_long(); # \$trade_state = \$long; # } else { # # remain short # \$sar = sar_calculation(); # if (\$low < \$prev_ep) { # if (\$af < \$af_max) { # \$af = \$af + \$af_increment; # } # \$ep = \$low; # } # } # } #} # #sub change_direction { # my (\$state) = @_; # my \$Result = 0; # if (\$state == \$long) { # # Change from long to short? # \$Result = \$low < \$prev_sar; # } else { # # Change from short to long? # die if \$state != \$short; # \$Result = \$high > \$prev_sar; # } # return \$Result; #} # #sub switch_to_short { # \$sar = \$prev_ep; # \$af = \$af_increment; # \$ep = \$low; # print "[S] " #} # #sub switch_to_long { # \$sar = \$prev_ep; # \$af = \$af_increment; # \$ep = \$high; # print "[L] " #} # #sub report { # print "(\$date) "; # print "af: \$af "; # print "ep: \$ep "; # printf ("sar:%.4f ", \$sar); # \$ref_af = \$a[3]; # \$ref_ep = \$a[4]; # \$ref_sar = \$a[5]; # print "(refs: \$ref_af \$ref_ep \$ref_sar) "; # if (! req(\$af, \$ref_af)) { # print "[af differs]"; # \$succeeded = 0; # } # if (! req(\$ep, \$ref_ep)) { # print "[ep differs]"; # \$succeeded = 0; # } # if (! req(\$sar, \$ref_sar)) { # print "[sar differs]"; # \$succeeded = 0; # } # print "\n"; #} # #sub req { # my (\$r1, \$r2) = @_; # return abs (\$r1 - \$r2) < .0001; #} e c n ONE_VARIABLE_FUNCTION c Parabolic SAR No Input Function y NUMERIC_VALUED_COMMAND_WRAPPER e Root # This is the top-level command sequence, which includes an initialization # section, run only for the first period, a main body, three assignments to # update the previous AF, EP, and SAR, and the SAR value by itself to # provide the result of the calculation. COMMAND_SEQUENCE e Main sequence y NUMERIC_CONDITIONAL_COMMAND e If 1st period, Init; else main body EQ_OPERATOR e First period? UNARY_LINEAR_OPERATOR e Period number No Input Function y INDEX_EXTRACTOR c shared UNARY_LINEAR_OPERATOR (Period number) c NUMERIC_VALUE_COMMAND e One n 1 NUMERIC_VALUED_COMMAND_WRAPPER e Initialization # The Initialization sequence - only executed for the first period, # consisting of "variable" and "constant" initializations COMMAND_SEQUENCE e Initialization sequence y NUMERIC_VALUE_COMMAND e Previous SAR value n 0 n y NUMERIC_VALUE_COMMAND e Previous EP value n 0 n y NUMERIC_VALUE_COMMAND e Previous AF value n 0 n y NUMERIC_VALUE_COMMAND e short n -1 n y NUMERIC_VALUE_COMMAND e AF increment y .02 n y NUMERIC_VALUE_COMMAND e Maximum AF value y .1999 n y NUMERIC_VALUE_COMMAND e Null operation n 0 n y NUMERIC_ASSIGNMENT_COMMAND e tradestate := long NUMERIC_VALUE_COMMAND e tradestate n 0 NUMERIC_VALUE_COMMAND e long n 1 n y NUMERIC_ASSIGNMENT_COMMAND e SAR := low NUMERIC_VALUE_COMMAND e SAR n 0 LOW_PRICE c n y NUMERIC_ASSIGNMENT_COMMAND e EP := high NUMERIC_VALUE_COMMAND e EP n 0 HIGH_PRICE c n y NUMERIC_ASSIGNMENT_COMMAND e AF := Initial AF value NUMERIC_VALUE_COMMAND e AF n 0 NUMERIC_VALUE_COMMAND e Initial AF value y .2 n n # The main body, executed on periods 2 to the end of the data - Corresponds # to the 'execute' routine in the perl script. NUMERIC_CONDITIONAL_COMMAND e Main body EQ_OPERATOR e tradestate = long? shared NUMERIC_VALUE_COMMAND ({tradestate}) c shared NUMERIC_VALUE_COMMAND ({long}) c # Corresponds to the "long block" in the perl script. NUMERIC_CONDITIONAL_COMMAND e Long block OR_OPERATOR e Change direction? AND_OPERATOR c shared EQ_OPERATOR (tradestate = long?) c LT_OPERATOR c shared LOW_PRICE c shared NUMERIC_VALUE_COMMAND ({Previous SAR value}) c AND_OPERATOR c EQ_OPERATOR e tradestate = short? shared NUMERIC_VALUE_COMMAND ({tradestate}) c shared NUMERIC_VALUE_COMMAND ({short}) c GT_OPERATOR c shared HIGH_PRICE c shared NUMERIC_VALUE_COMMAND ({Previous SAR value}) c NUMERIC_VALUED_COMMAND_WRAPPER e Switch to short # This section orresponds to the 'switch_to_short' routine in the perl # script - executed when 'long' and 'Change direction?' is true. COMMAND_SEQUENCE e "Switch to short" sequence y NUMERIC_ASSIGNMENT_COMMAND e SAR := Previous EP value shared NUMERIC_VALUE_COMMAND ({SAR}) c shared NUMERIC_VALUE_COMMAND ({Previous EP value}) c n y NUMERIC_ASSIGNMENT_COMMAND e AF := AF increment shared NUMERIC_VALUE_COMMAND ({AF}) c shared NUMERIC_VALUE_COMMAND ({AF increment}) c n y NUMERIC_ASSIGNMENT_COMMAND e EP := low shared NUMERIC_VALUE_COMMAND ({EP}) c shared LOW_PRICE c n y NUMERIC_ASSIGNMENT_COMMAND e tradestate := short shared NUMERIC_VALUE_COMMAND ({tradestate}) c shared NUMERIC_VALUE_COMMAND ({short}) c n n NUMERIC_VALUED_COMMAND_WRAPPER e Remain long # This section corresponds to the "remain long" block in the perl script. # It updates SAR and, conditionally, updates AF and EP. COMMAND_SEQUENCE e "Remain long" sequence y NUMERIC_ASSIGNMENT_COMMAND e Update SAR shared NUMERIC_VALUE_COMMAND ({SAR}) c ADDITION e SAR calculation MULTIPLICATION c SUBTRACTION c shared NUMERIC_VALUE_COMMAND ({Previous EP value}) c shared NUMERIC_VALUE_COMMAND ({Previous SAR value}) c shared NUMERIC_VALUE_COMMAND ({Previous AF value}) c shared NUMERIC_VALUE_COMMAND ({Previous SAR value}) c n y NUMERIC_CONDITIONAL_COMMAND c GT_OPERATOR e High > Previous EP? shared HIGH_PRICE c shared NUMERIC_VALUE_COMMAND ({Previous EP value}) c NUMERIC_VALUED_COMMAND_WRAPPER c COMMAND_SEQUENCE c y NUMERIC_CONDITIONAL_COMMAND e AF increment condition LT_OPERATOR e AF < Maximum AF value? shared NUMERIC_VALUE_COMMAND ({AF}) c shared NUMERIC_VALUE_COMMAND ({Maximum AF value}) c NUMERIC_ASSIGNMENT_COMMAND e Increment AF shared NUMERIC_VALUE_COMMAND ({AF}) c ADDITION e AF + AF increment shared NUMERIC_VALUE_COMMAND ({AF}) c shared NUMERIC_VALUE_COMMAND ({AF increment}) c shared NUMERIC_VALUE_COMMAND ({Null operation}) c n y shared NUMERIC_ASSIGNMENT_COMMAND (EP := high) c n n shared NUMERIC_VALUE_COMMAND ({Null operation}) c n n # Corresponds to the "short block" section of the perl script. NUMERIC_CONDITIONAL_COMMAND e Short block shared OR_OPERATOR (Change direction?) c NUMERIC_VALUED_COMMAND_WRAPPER e Switch to long # This section orresponds to the 'switch_to_long' routine in the perl # script - executed when 'short' and 'Change direction?' is true. COMMAND_SEQUENCE e "Switch to long" sequence y shared NUMERIC_ASSIGNMENT_COMMAND (SAR := Previous EP value) c n y shared NUMERIC_ASSIGNMENT_COMMAND (AF := AF increment) c n y shared NUMERIC_ASSIGNMENT_COMMAND (EP := high) c n y shared NUMERIC_ASSIGNMENT_COMMAND (tradestate := long) c n n NUMERIC_VALUED_COMMAND_WRAPPER e Remain short # This section corresponds to the "remain short" block in the perl script. # It updates SAR and, conditionally, updates AF and EP. COMMAND_SEQUENCE e "Remain short" sequence y shared NUMERIC_ASSIGNMENT_COMMAND (Update SAR) c n y NUMERIC_CONDITIONAL_COMMAND c LT_OPERATOR e Low < Previous EP? shared LOW_PRICE c shared NUMERIC_VALUE_COMMAND ({Previous EP value}) c NUMERIC_VALUED_COMMAND_WRAPPER c COMMAND_SEQUENCE c y shared NUMERIC_CONDITIONAL_COMMAND (AF increment condition) c n y shared NUMERIC_ASSIGNMENT_COMMAND (EP := low) c n n shared NUMERIC_VALUE_COMMAND ({Null operation}) c n n n y # The three assignment constructs below are executed last for each # period. They are equivalent to these lines from the perl script: # \$prev_sar = \$sar; # \$prev_af = \$af; # \$prev_ep = \$ep; NUMERIC_ASSIGNMENT_COMMAND e Previous SAR := SAR shared NUMERIC_VALUE_COMMAND ({Previous SAR value}) c shared NUMERIC_VALUE_COMMAND ({SAR}) c n y NUMERIC_ASSIGNMENT_COMMAND e Previous AF := AF shared NUMERIC_VALUE_COMMAND ({Previous AF value}) c shared NUMERIC_VALUE_COMMAND ({AF}) c n y NUMERIC_ASSIGNMENT_COMMAND e Previous EP := EP shared NUMERIC_VALUE_COMMAND ({Previous EP value}) c shared NUMERIC_VALUE_COMMAND ({EP}) c n y # This last sub-operator of the main command sequence is required in order # to provide the resulting value of the calculation for the period: SAR. shared NUMERIC_VALUE_COMMAND ({SAR}) c y n s - x ```