1. 首页
2. 易语言 - EasyLanguage
3. 关于函数Understanding Functions

# 关于函数Understanding Functions

1. What are functions and what are they for?

Functions are self-contained pieces of EasyLanguage code that are ‘called’ by indicators, strategies or other functions. They ‘return’ a value or values that can be used by the ‘calling’ code. Functions are used to reduce the amount of code that needs to be written, reduce repetition, reduce mistakes and generally simplify code.

As an example, if you want to know the average price over the last 10 bars (a simple moving average) you would say

```value1 = Average(Close, 10);
```

‘Average’ is a function for calculating simple moving averages. Rather than having to work out the math yourself, write the code to calculate the average, and then repeat that code every time you want to calculate a moving average, you just call this function with a price (Close) and a length (10) and it does the calculation for you. The value of the 10 bar moving average based on the closing price is then held in the ‘value1’ variable.

There are a large number of functions provided by TradeStation, and many users have also written and shared their own functions on the TradeStation forums.

To see all of the functions that you have access to, from TradeStation choose the ‘File’ menu, then ‘Open EasyLanguage Document…’, then change the ‘Select Analysis Type:’ dropdown to ‘Function’.

This is a list of ALL functions you have installed, including both TradeStation supplied functions, ones that have been installed with indicators and strategies, and any that you have written yourself.

Note the Fx next to each function name. If this is red then it means the function is ‘read only’. These are standard functions supplied by TradeStation that you cannot change. (You can still view the code in these functions, so if you want to make any changes you should open the function, copy the code and create a new function with a similar name). When Fx is in green it means that you can both read and write the function. Not all TradeStation supplied functions are read-only, some can be modified (no idea why?). Making a function read-only can only be done by TradeStation – it is not functionality you have access to.

2. Functions vs. Reserved Words

Functions are different from Reserved Words. Functions are written in EasyLanguage code and can be accessed (and rewritten). Reserved Words are part of the TradeStation program. They are not written in EasyLanguage, and their code cannot be accessed. In the EasyLanguage document editor Reserved Words are highlighted in blue whereas Functions are highlighted in dark magenta.

Reserved Words have much better performance than Functions, and should be used in preference to Functions whenever possible.

3. Calling Functions from Indicators and Strategies

The syntax for calling functions depends on the number of parameters you are passing to the function, and the number of values it is returning. There are basically three different ways to call functions, depending on the function and how it is written.

No inputs, a single return value.

```Vars:	returnval(0);

returnval = BarNumber;```

After this function is called returnval will contain the bar number that the code is currently running on.

One or more inputs, a single return value.

```Vars:	returnval(0);

returnval = Average(Close, 10);```

In this example, there are two inputs – a price (Close) and a length(10) – and a single value is returned. returnval will contain a value of the 10 bar moving average.

One or more inputs, multiple return values.

```Vars:	returnval(0),
oLRSlope(0), oLRAngle(0), oLRIntercept(0), oLRValue(0);

returnval = LinearReg( Close, 10, 0, oLRSlope, oLRAngle, oLRIntercept, oLRValue );
```

In this example, there are three inputs – Price (Close), Length (10) and TargetBar (0) – and five outputs – returnvaloLRSlopeoLRAngleoLRIntercept and oLRValue. A function that returns more than one value is known in EasyLanguage as a Multiple-Output Function. Note the variable names for values returned by the function all start with an ‘o’. This is purely a convention we use in EasyLanguage so it is easy to see which variables the function is changing. This isn’t necessary, but it makes our code consistent and easier to understand.

The return values of functions can also be of different types, depending on the function. They can be string values, boolean (true/false) values, or numeric values (integer, double, float).

To know how to call a function you need to either read the documentation for that particular function or open the function and read how it is constructed in EasyLanguage. Most TradeStation supplied functions are documented. When editing an EasyLanguage document, if you type in a function name it will turn dark magenta in color. If you right click on the function name and choose ‘Definition of …’ it will give you the help for that function.

Non-TradeStation functions will not have this help documentation.

By right clicking on the function name and choosing ‘Open the Function – xxx’ you can open the EasyLanguage code for that function and see what parameters it needs.

4. Simple vs. Series Functions

EasyLanguage has two types of functions – Simple and Series – which have very important differences. A Series function references a previous value of itself, whereas a Simple function does not. For example, this function, MySimpleFunction, has no previous references to itself so it is Simple:

```Vars: MyVal(0);

MyVal = CurrentBar;

MySimpleFunction = MyVal;```

Whereas, this function, MySeriesFunction, refers to previous values of itself so it is Series:

```Vars: MyVal(0), MyVal_prev(0);

MyVal = CurrentBar;
MyVal_prev = MyVal;  //referencing a previously calculated value

MySeriesFunction = MyVal_prev;```

The function type can be set under the function properties…

The default value is ‘Auto-Detect’ and in this case any self-reference will force the function to be a ‘Series’ type. If you attempt to set this setting to ‘Simple’ when the function references itself then the verification process will produce an error. You can force a Simple function to be Series by setting the Property: Function Storage Type to ‘Series’.

There are several important differences between the way Simple and Series functions are processed in EasyLanguage which will affect how your code runs.

4.1 Testing functions for ‘Simple-ness’ and ‘Series-ness’

This piece of code is known as eKam’s Function Test.

```if False then begin
value1 = MySimpleFunction;
value2 = MySeriesFunction;
end;```

The conditional statement is always false (‘if False then begin’) so, in theory, neither function should ever run. However, if you have a print statement in both functions, you will see that the MySeriesFunction function outputs on every bar. Any function that runs on every bar, even though it has a false conditional, is a Series function.

4.2 Conditional Statements

An important difference between Simple and Series functions is how they are processed in conditional statements. A Simple function is only processed if the condition is True, whereas a Series function is processed regardless of whether the condition is True or False. Furthermore, for Series functions, a conditional statement that evaluates to False causes the function to evaluate at the very end of the code – after all other code has finished processing – and it uses the values of variables that are present at the end of the code rather then those when it was called.

Let’s look at an example to explain these differences in more detail.

In this code, the two functions will run on every bar because the conditional statement (if True then…) is always true

```value1 = 10;
if True then begin
value5 = MySimpleFunction(value1);
value6 = MySeriesFunction(value1);
end;
value1 = 20;```

Both the Simple and Series function are called with a parameter (value1). In this case value1 has been set to 10, so they are both called with a parameter of 10.

In this code, the first statement, calling a Simple function, will never be called. This is because the conditional statement (if False then…) is always false.

```value1 = 10;
if False then begin
value5 = MySimpleFunction(value1);
value6 = MySeriesFunction(value1);
end;
value1 = 20;```

However, the second statement, calling a Series function, is called on every bar, even though the conditional statement is false. However, the Series function is not called on the line number where you see it, but rather at the very end of the code, when all other code has finished processing. Because the parameter used by the function (value1) has had its value changed before the end of the code, it means that the Series function is actually called with a 20, rather than 10. This may seem confusing and illogical but it is the way EasyLanguage works (and there are good reasons for it).

In general, to avoid the types of issues described here, it is best not to put any functions in conditional statements. For example, rather than writing…

`if average(close, 10) > average(close, 20) or RSI(Close, 7) < RSI(Close, 14) then xxx;`

…it is best to write…

```condition1 = Average(Close, 10) > Average(Close, 20);
condition2 = RSI(Close, 7) < RSI(Close, 14);
if condition1 and condition2 then xxx```

This method guarantees that functions are properly evaluated.

4.3 Every bar/tick processing

If you follow the logic from above, it means that Series functions will run on every single tick/bar on the chart.

Conditional coding e.g. (If Low > High then) will prevent any processing of code following the test if the test evaluates to false – unless the following code contains series functions (functions which access past values of themselves). Series functions will run on every tick and at every bar end, regardless of any conditional tests.

An important difference between Simple and Series functions is how they are processed in conditional statements. A Simple function is only processed if the condition is True, whereas a Series function is processed regardless of whether the condition is True or False. Furthermore, for Series functions, a conditional statement that evaluates to False causes the function to evaluate at the very end of the code – after all other code has finished processing – and it uses the values of variables that are present at the end of the code rather then those when it was called.

4.4 Duplicating Function Calls

Series functions must not be called multiple times with the same parameter names.

The following code will produce incorrect results

```X = 10;
value1 = MySeriesFunction(X);
X = 20;
value2 = MySeriesFunction(X);```

Because the function is being called twice with the same parameter name (X) EasyLanguage can’t differentiate between the two calls. Even though the value of the parameter X has changed from 10 to 20, EasyLanguage thinks that the function is only being called once. It ‘forgets’ the first call and only retains the value of the second call.

To call the same Series function multiple times with different values you would use

```X = 10;
value1 = MySeriesFunction(X);
Y = 20;
value2 = MySeriesFunction(Y);```

In this case the first call is with ‘X’ and the second is with ‘Y’, and hence EasyLanguage can differentiate between these two calls and calculate them both correctly.

4.5 Loops
Series functions must not be called from within For, While or Repeat-Until loops.

4.5.1 Variable in Functions

4.5.2 For a test, use the ‘false’ statements which is only and always evaluated if it calls a series functions

4.5.3 IFF Functions

If the test is TRUE,  processing should stop when the condition is true and then skip to the end of the IFF statement. But the “FALSE” condition will be evaluated if it calls a series function. Series functions, unlike simple functions, are called on every bar. For this reason, series functions should, in general, not be used in looping structures or placed behind conditional statements (for example, the IFF function).

5. Writing Functions

5.1 Variable persistance within functions

5.2 Functions Return Types

Inputs types:
Numeric
NumericRef
NumericArray
NumericArrayRef
NumericSeries
NumericSimple
String
StringRef
StringArray
StringArrayRef
StringSeries
StringSimple
TrueFalse
TrueFalseRef
TrueFalseArray
TrueFalseArrayRef
TrueFalseSeries
TrueFalseSimple

5.3 Passing Arrays

6. Performance and ‘In-line’ code

Writing code in functions has many benefits. However, there is one drawback – performance. Code written directly in an indicator will run faster then exactly the same code written in a function and then called from the indicator.

So, in general, you can increase the performance of TradeStation by rewriting your indicators so that they don’t call functions, but instead all the code is contained within a single indicator (or strategy). In TradeStation terminology we refer to the process of moving EasyLanguage code out of a function into an indicator as making it ‘In-Line’. (Note that this is a different meaning from other programming languages such as C/C++. The concept of ‘In-Line’ functions as used in C/C++ is not available in EasyLanguage.)

7. Best Practice for working with Functions

• Use Reserved Words in preference to Functions whenever possible. Reserved Words are much faster.
• Return function values to a variable, then use that variable in the next function’s call. A mix of Simple and Series functions or use of the ExecOffset reserved word can mean calling functions within functions returns incorrect results.

The following dos and donts refer specifically to Series functions. You can use Simple functions in all these cases without any problems. However, it is very difficult to differentiate between Series and Simple functions. Even if the function you are calling is definately Simple, it may be calling a function that is Series, or it may call a Simple function that calls a Simple function that calls a Series function etc. If there are any ‘downstream’ Series functions then you will get problems. For that reason it is best (for your code quality and for your sanity) to regard these dos and donts as applying to all functions.

• Don’t call functions within conditional statements. Series functions can return incorrect results if called within conditional statements.
• Separate each function call onto its own line. Series functions can return incorrect results if several are called on the same line.
• Don’t call the same function multiple times with the same parameter names. Series functions called multiple times with the same parameter set will produce incorrect results.
• Don’t call functions within loops. Series functions will return incorrect results if called within loops.

8. Common Questions & Issues

1. Can I add help documentation so that a Function I write can be documented?

No, this is not possible.

2. Can I make my function ‘read only’, like TradeStation supplied functions? i.e. you can see the code but you can’t edit it.

No. This can only be done by TradeStation.

3. Can I make my function so that others can’t see my code?

Yes, please see the article Security and Code Protection.

4. I am getting this error when I try to verify my function.

You have set the property of the function to be ‘Simple’ but it contains a self-reference making it a ‘Series’ function. You must change the property back to ‘Auto-Detect’ or ‘Series’.

5. I can see the EasyLanguage code for functions, but how do I get the EasyLanguage code for Reserved Words?

Reserved Words are not written in EasyLanguage. They are part of the TradeStation program and are not accessible to users.

6. How do I make changes to one of TradeStation’s read-only functions?

You can’t change the function directly. But you can make a copy of it and change the copy. Simply open the function, copy all, then create a new function with a similar name and post the code into this new function. Then you just need to change any references from the old name to the new.

7. When I try to verify my function I get the error ‘A value was never assigned to user function’. What does this mean?

All functions must return a value. Somewhere in the function code it must say ‘functionname = value;’, where functionname is the name of your function, and value is a boolean, numeric or string value that is being returned.

8. When I try to verify my function I get the error ‘Assignment to a function not allowed’. What does this mean?

This usually means that the function name is different from that in the code. For instance, if your function is called ‘Test1’, then you have a line in your code saying ‘Test*2* = 0;’.

9. When I try to verify my function I get an error. What does this mean?

These errors can happen anywhere in your code where you have defined a variable as one type (boolean, numeric or string) but are then trying to assign a value of a different type to it (e.g. if you declare a value as a number and then try to assign ‘True’ to it). Functions also need to return a value of some kind, and this error can occur if you try to return the wrong type of value. The function’s return value type is specified in its property settings. See section 5 above on Writing Functions.