Introduction
The “Raw Code Output (Single or Multiple Statements)” action allows you to add a single statement or multiple statements at your chosen location in the code output by providing you with a text box where you can write actual code in the programming language that a given edition of the Quagensia® Desktop Application outputs.
The “Raw Code Output (Single or Multiple Statements)” action also fulfills an additional essential role in Quagensia T Edition by enabling Quagensia T Edition Action Functions to do the kinds of advanced calculations that are not possible in Quagensia T Edition Expression Functions due to the limitation that Quagensia T Edition Expression Functions are limited to doing the kinds of calculations that can be done in a single line of code with no local variables to store intermediate results. A detailed discussion of this for Quagensia T Edition users is further down on this page.
This is an advanced feature that is used primarily by authors of functions that need to output raw code.
Most Quagensia Action Functions that come with your edition of Quagensia use a “Raw Code Output (Single or Multiple Statements)” action as a way to translate the uses of the visual, codeless Quagensia Function in all the Quagensia Algos in your installation of your edition of Quagensia into actual trading strategy code.
Note that you can insert a reference to an input parameter or an internal variable by right clicking in the text box at the desired location, then selecting the input parameter or internal variable whose reference you want to insert at that location.
When you do this, you will notice that a reference of this type looks like {|~Var~The_Name_Of_Your_Variable_Goes_Here~A_Long_String_Of_Letters_And_Numbers_Goes_Here~|}. Although you are free to type this by hand, inserting placeholders via the “Insert Placeholder” context menu is much easier and less error-prone.
Defining Local Variables in Code (Quagensia N Edition Only)
If you are defining local variables in your raw text, make your variable names distinctive or unique, particularly by making them long enough and not the name of a trading concept or programming concept, so that there is only an extremely small chance that the variable name conflicts with another object, variable, object member, parameter name, or keyword of the trading platform on which this algo is meant to run.
Good variable names are long like “myVolumeThreshold1” or “myCriticalBreakoutLevel”. Examples of bad variable names are “Volume”, “High”, “int”, and “bool” because they sound like they might be a keyword or object name in the base language or API used by a trading platform’s programming model.
Defining Variables in Code (Quagensia T Edition Only)
Unlike Quagensia N Edition, Quagensia T Edition doesn’t have the ability to output function definitions with their own set of local variables, nor does Quagensia T Edition allow you to define local variables by defining them by typing them in code verbatim, nor does Quagensia T Edition allow you to create a Quagensia T Edition Expression Function with anything other than a single “Exit Function With This Return Value” action whose return value is set to an expression (which will often be a “Raw Code Output” expression but doesn’t have to be). Quagensia T Edition does however offer you a way to accomplish something similar to a complex Quagensia N Edition Expression Function containing thousands of lines of code and many local variables by allowing you to create variables that are defined globally in the EasyLanguage® strategy whose code Quagensia T Edition outputs but that you can use inside of the “Raw Code Output” text boxes of “Raw Code Output (Single or Multiple Statements)” actions in Quagensia T Edition Strategies and Functions and then use the variables as though they are “Local to a single Raw Code Output text box” or “Local to all Raw Code Output text boxes in a single algo”, so long as you follow some easy to remember rules.
Defining and using these kinds of variables is not supported in the “Raw Code Output” expression, but you can accomplish a similar thing using the “Raw Code Output (Single or Multiple Statements)” action, which allows you to do complex calculations using thousands of lines of code and a very large number of variables, and then set an internal variable in a Quagensia T Edition strategy or an input parameter passed by reference to a Quagensia T Edition action function with the result of the calculation, which then becomes available outside of the “Raw Code Output (Single or Multiple Statements)” action’s “Raw Code Output” text box for use as a standard codeless, visual variable reference that can be used like any other variable reference to any input parameter or internal variable defined in a Quagensia Algo.
You can right click in the “Raw Code Output” text box at the desired location in order to insert different kinds of variables using the context menu that appears.
In addition to the “standard variable” insertion, which allows you to insert a reference to an input parameter or an internal variable, and is available in all editions of Quagensia, Quagensia T Edition makes it possible to insert a variable of one of the five non-standard variable types, which are as follows:
- Global Variable for a Single Text Box
- Global Variable for Multiple Text Boxes
- Global Wildcard Variable for a Single Text Box
- Global Wildcard Variable for Multiple Text Boxes
- Type Name of the Expected Data Type of a Wildcard Input Parameter
You can learn more about these non-standard variable types in the tooltips of the corresponding context menu items and in the documentation below. Note that not all non-standard variable types are supported in “Raw Code Output” text boxes in all locations, and context menu items only appear for each of the five non-standard variable types when they are supported at the location of the “Raw Code Output” text box that was right clicked.
Non-Standard Variable Types #1 and #2: Global Variables for a Single Text Box or Multiple Text Boxes (Quagensia T Edition Only)
When you right click on the “Raw Code Output” text box of a “Raw Code Output (Single or Multiple Statements)” action in a Quagensia T Edition Algo, the context menu items in the “Insert Placeholder >> Advanced Variable Placeholders” context menu folders titled “New Global Variable for a Single Text Box” and “New Global Variable for Multiple Text Boxes” have subfolders for each supported data type, and inside those folders are context menu items that let you visually insert up to 100 separate global variable definitions at the strategy level (not local variables inside of a function) and insert references to these newly defined variables at your chosen location in the code output.
Note that while you can only insert up to 100 separate global variables per supported data type from their own context menu items, Quagensia supports up to 99,999 separate global variables per supported data type, but variable placeholders with numbers above 100 must be typed by hand. You can do this quickly by simply copying another variable placeholder and pasting it to a desired location, and then changing its number to a value between 1 and 99999.
Global variables for a single text box or multiple text boxes make it possible to define, set, and use a variable in either 1) a Quagensia Strategy, or 2) a Quagensia Function that outputs its code not as a function definition but instead as inlined code inserted at the location that the function is called, which is the only way that Quagensia Function code is outputted for the TradeStation® platform.
Since both “Global Variable for a Single Text Box” variables and “Global Variable for Multiple Text Boxes” variables are nothing more than global variables in the EasyLanguage® strategy whose code Quagensia T Edition outputs, you must assume that these variables have garbage data in them unless:
- The variable is a “Global Variable for a Single Text Box” variable and the variable has literally just been set to a value in the current line of code or in a line of code above the current line of code in the current “Raw Code Output” text box.
- The variable is a “Global Variable for Multiple Text Boxes” variable and the variable has literally just been set to a value in the current line of code or in a line of code above the current line of code in the current “Raw Code Output” text box or if the variable has just been set to a value in any “Raw Code Output” text box whose code will be executed earlier in the same Quagensia Strategy’s “When Bar Updates” section or the same Quagensia Function’s “Function Logic” section as the current “Raw Code Output” text box).
The practical implication of the two rules above are as follows:
- You must set and use a “Global Variable for a Single Text Box” variable all within the same “Raw Code Output” text box, and you must set it before you attempt to use it.
- You must set and use a “Global Variable for Multiple Text Boxes” variable all within the same Quagensia Algo, and you must set it before you attempt to use it.
The two rules and their two implications above dictate when it is best to use a “Global Variable for a Single Text Box” variable and when it is best to use a “Global Variable for Multiple Text Boxes” variable.
When to Use a “Global Variable for Multiple Text Boxes” Variable
If you need to use a global variable in more than one “Raw Code Output” text box in the same Quagensia Algo, i.e. you want to set the global variable in one “Raw Code Output” text box and use the value that the variable was set to in another “Raw Code Output” text box whose code will be executed later in the same Quagensia Strategy’s “When Bar Updates” section or the same Quagensia Function’s “Function Logic” section then you should use a “Global Variable for Multiple Text Boxes” variable instead of a “Global Variable for a Single Text Box” variable.
This is because the values of “Global Variable for Multiple Text Boxes” variables will not be overwritten due the calling of a Quagensia Function in between two “Raw Code Output” text boxes in the same Quagensia Algo even if the Quagensia Function being called or one of the Quagensia Functions called directly or indirectly by the Quagensia Function being called coincidentally uses the same placeholder, such as “{|~GlobalMTBVar~Int~3~|}”, with the same data type (“Int”) and the same number (“3”).
The reasons why “Global Variable for Multiple Text Boxes” variables can be relied upon to exhibit the behavior above is as follows:
- Identical “Global Variable for Multiple Text Boxes” variable placeholders in different Quagensia Algos are outputted with different global variable names in the EasyLanguage® strategy code output, so setting a “Global Variable for Multiple Text Boxes” variable via the line “{|~GlobalMTBVar~Int~3~|} = 123;” in one Quagensia Algo won’t overwrite the value of the global variable represented by “{|~GlobalMTBVar~Int~3~|}” in another Quagensia Algo.
- A Quagensia Function cannot call itself either directly (i.e. “Function A” calls “Function A” recursively) or indirectly (i.e. “Function A” calls “Function B”, which calls “Function C”, which calls “Function A” in a cycle), because the Quagensia validation engine disallows Quagensia Function calls from forming “cycles”.
When to Use a “Global Variable for a Single Text Box” Variable
“Global Variable for a Single Text Box” variables are a good choice if you only use a given variable within a single “Raw Code Output” text box.
The main benefit of using “Global Variable for a Single Text Box” variables is that the EasyLanguage® strategy code may have less variable definitions, and the names of the variables will be simpler. This will make your EasyLanguage® strategy code easier to read and will cause your EasyLanguage® strategy to execute faster. The speed increase when compared to using “Global Variable for Multiple Text Boxes” variables will be unnoticeable in most cases, but this depends on the difference in the number of variable definitions outputted to the EasyLanguage® strategy code.
The reason that “Global Variable for a Single Text Box” variables may produce less variables and will produce variables with simpler variable names is because the variable defined in EasyLanguage® strategy code output for a single variable placeholder for a “Global Variable for a Single Text Box” variable, such as “{|~GlobalSTBVar~Int~3~|}”, will be reused by an unlimited number of other Quagensia Functions and will be reused by an unlimited number of function uses of the Quagensia Function in which the variable placeholder was used. For instance, if “{|~GlobalSTBVar~Int~3~|}” was used in ten Quagensia Functions that a Quagensia Strategy uses directly or indirectly via calls to other Quagensia Functions, and each of the ten Quagensia Functions is used three times (note that a single visual codeless Quagensia Function call in a loop that is called 100 times due to the loop calling the same code 100 times still counts as “one use”), there will still only be one variable placeholder in the EasyLanguage® strategy code output. Had we used a “Global Variable for Multiple Text Boxes” variable placeholder, such as “{|~GlobalMTBVar~Int~3~|}”, in the example above, 30 separate variables would be generated, one for each of the 10 x 3 = 30 uses of functions that use that variable placeholder. Also, the names of the variables would be longer and more complicated as well so that each of the 30 variables can be distinguished from each other and store separate values.
Non-Standard Variable Types #3 and #4: Global Wildcard Variables for a Single Text Box or Multiple Text Boxes (Only Used In Quagensia T Edition Action Functions That Accept Wildcard Input Parameters)
When you right click on the “Raw Code Output” text box of a “Raw Code Output (Single or Multiple Statements)” action in a Quagensia T Edition Action Function with one or more “Wildcard (Any Simple Data Type)” input parameters, the context menu items in the “Insert Placeholder >> Advanced Variable Placeholders” context menu folders titled “New Global Wildcard Variable for a Single Text Box” and “New Global Wildcard Variable for Multiple Text Boxes” context menu subfolders let you insert up to 100 separate global wildcard variable definitions at the strategy level (not local variables inside of a function) and insert references to these newly defined variables at your chosen location in the code output. The actual data type of the variable outputted to the EasyLanguage® strategy code will be dependent on the expected data type of the expression (or the wildcard portion of the expression if its data type is a collection of wildcard elements, such as an array of wildcards) that is passed into the first wildcard input parameter of the Quagensia T Edition Action Function.
Note that while you can only insert up to 100 separate global wildcard variables from their own context menu items, Quagensia supports up to 99,999 separate global wildcard variables, but variable placeholders with numbers above 100 must be typed by hand. You can do this quickly by simply copying another variable placeholder and pasting it to a desired location, and then changing its number to a value between 1 and 99999.
To learn about “Global Wildcard Variable for a Single Text Box” variables and “Global Wildcard Variable for Multiple Text Boxes” variables and how to use them, read the documentation about “Global Variable for a Single Text Box” variables and “Global Variable for Multiple Text Boxes” variables above this section, and just remember that the wildcard versions of these two non-standard variable types are only for wildcard input parameters of Quagensia T Edition Action Functions rather than for general use with any kind of simple non-wildcard data type, like “Whole Number” or “Decimal Number”, which can be used in both Quagensia T Edition Strategies and Quagensia T Edition Action Functions.
Non-Standard Variable Type #5: Type Name of the Expected Data Type of a Wildcard Input Parameter (Only Used In Quagensia T Edition Action Functions That Accept Wildcard Input Parameters)
When you right click on the “Raw Code Output” text box of a “Raw Code Output (Single or Multiple Statements)” action in a Quagensia T Edition Action Function with one or more “Wildcard (Any Simple Data Type)” input parameters, the context menu item at the bottom of the “Insert Placeholder >> Advanced Variable Placeholders” context menu folder is titled either “Type Name of the Expected Data Type of the Elements of ‘<The Wildcard Input Parameter’s Name>’ in the Code Output” or “Type Name of the Expected Data Type of ‘<The Wildcard Input Parameter’s Name>’ in the Code Output”, depending on whether or not the first input parameter that uses a wildcard data type is a collection of items, such as a list, array, or time series.
When you click on this context menu item, a “Type Name of the Expected Data Type of a Wildcard Input Parameter” placeholder is inserted in the text box at the desired location. It looks like this:
{|~WildcardVarDataTypeName~The_Name_Of_A_Wildcard_Based_Input_Parameter_Goes_Here~A_Long_String_Of_Letters_And_Numbers_Goes_Here~|}
This placeholder gets replaced with the name of the expected data type, for example “int” or “double”, of the expression that is passed into the first input parameter of the Quagensia Function that uses a wildcard (or the wildcard portion of the input parameter’s data type if its data type is a collection of wildcard elements, such as an array of wildcards), which is determined at the time that this placeholder is outputted to the EasyLanguage® strategy code.
One common use of the “Type Name of the Expected Data Type of a Wildcard Input Parameter” feature is in conjunction with the EasyLanguage® keyword “astype” in order to use “casting” to get an item into or out of a Quagensia list, which is an EasyLanguage® vector, without causing either a compilation error in the EasyLanguage® development environment or a runtime error when you use your strategy within the TradeStation® environment.
EasyLanguage® vectors store their items in the “object” data type rather than as the data type of the items that were placed into the vector. Even if you add an item that is a decimal number, i.e. of the “double” data type, to an EasyLanguage® vector, if you try to then set the value of a decimal variable to the item in the EasyLanguage® vector that holds the decimal number, a compilation error will occur. However, if you “cast” the value that you extract from the EasyLanguage® vector into a decimal, i.e. a “double”, and then set the decimal number variable to the value you “cast” to the “double” data type, no compilation error occurs.
For instance, if “AWholeNumberVariable” is a variable of data type “int” and “AVectorOfWholeNumbers” is an EasyLanguage® vector that you know contains whole numbers because you put them there, the first line of outputted code would cause a compilation error, whereas the second line of code would not:
// This line causes a compilation error
AWholeNumberVariable = AVectorOfWholeNumbers[0];
// This line uses “casting” with “astype” to avoid causing a compilation error
AWholeNumberVariable = AVectorOfWholeNumbers[0] astype int;
Futhermore, for numeric types it is even important to cast the value of an item you are putting into an EasyLanguage® vector into the data type that you want it to be when you take it out of the EasyLanguage® vector, because trying to cast an item that you are taking out of a EasyLanguage® vector into a numeric data type that you thought was the data type of the number but that EasyLanguage® determined was a different numeric data type may cause a runtime error when you use your strategy within the TradeStation® environment. This commonly happens when you put a literal number such as “1” into a vector that you intend to hold decimal (“double”) numbers, thinking that “1” is just a decimal number without a fractional component, but EasyLanguage® considers the number “1” as an integral number, not a decimal number, when used in this context. If you put the literal number “1” into an EasyLanguage® vector and then tried to get the item out of the vector and cast it as a “double”, this may cause a runtime error.
Here is the safe way to add a literal number to the end of an EasyLanguage® vector that you want to hold decimal (“double”) values called “AVectorOfDecimalNumbers”:
AVectorOfDecimalNumbers.Push_back(1 astype double);
Then, assuming for this example that the number you added is the first item in the EasyLanguage® vector, you can get the decimal number out of the first element of the vector and set a decimal variable named “ADecimalVariable” to the value of the item extracted from the vector without causing a compilation error using this line of code:
ADecimalVariable = AVectorOfDecimalNumbers[0] astype double;
The reason why the “Type Name of the Expected Data Type of a Wildcard Input Parameter” placeholder is so important is that if you are inside of a Quagensia T Edition Action Function that has a wildcard-based input parameter, it is impossible to know the name of the data type that should go after the keyword “astype” when you are creating the Quagensia T Edition Action Function. None of the examples above that use “astype” can be used verbatim when the wildcard data type is involved. The correct data type name to use can only be known when the strategy code of the strategy that uses this function is generated by Quagensia T Edition, because at that time it is possible to know the expected data type of the expression that is passed into the first input parameter of the Quagensia T Edition Action Function that uses a wildcard (or the wildcard portion of the input parameter if its data type is a collection of wildcard elements, such as an array of wildcards). To see many correct usages of using “astype” with this placeholder as well as using astype with data type names of non-wildcard data types, like “astype int”, search for “astype list” (without the double quotes) in the Quagensia search text box from within the Quagensia Desktop Application and open the functions in the search results whose “Algo Database Location” starts with “Algos from Quagensia >> Functions >> Actions >> More Actions >> Lists”. Here is an actual example of using this placeholder with “astype” in order to output the expected data type name of the elements of a list that is passed into a function input parameter that is a list with an element data type of “Wildcard (Any Simple Data Type)”:
{|~GlobalWildcardSTBVar~1~List~bf7ad6486c064a7fa2b896a07e958c5d~|} = ({|~Var~List~bf7ad6486c064a7fa2b896a07e958c5d~|}[{|~GlobalSTBVar~Int~91~|}] astype {|~WildcardVarDataTypeName~List~bf7ad6486c064a7fa2b896a07e958c5d~|});
The WildcardVarDataTypeName placeholder above will be replaced by “int” if the function is passed a list of whole numbers, but it will be replaced with “double” or “bool” if the function is passed a list of decimal numbers or Boolean (true or false) values.