The Cyber Code is a new feature for the Divine Engine, as part of the Evolutionary mode. It allows the Divine Engine to create trading indicators from scratch, by writing computer code on its own.
When the rest of the world use well-known indicators such as Moving Average, Relative Strength Index, or Bollinger Bands, here you'll keep your market edge even sharper with completely unique trading indicators. With the help of Genetic Programming, these codes evolve throughout the generations, in tandem with the evolution of strategies we already discussed. So it's an even more dynamic evolutionary progression, in which not only the strategies are evolving, but the codes as well, the nuts and bolts of each trading indicator.
You're not constrained to the rigid set of mathematical formula and specific market data as found in built-in trading indicators. Instead, the Cyber Code engine constructs and de-constructs myriad formulas, mixed in with various market data, to create the ultimate technical indicators.
Note, you need a certain license to access the Cyber Code engine. Please contact our Customer Support to upgrade your license.
This page is divided into three sections:
The use of Cyber Code is generally similar to the standard evolutionary backtest we discussed previously. The main difference is that the new rules (indicators) added by the Divine Engine are exclusively Cyber Code rules. None of the built-in indicators will be slapped to the strategies it created.
1. First, you must set the “Search Algorithm” property to “Evolutionary”.
2. Then get to the property “Rule Set Parameterization”, and choose the option “Generate Cyber Code” there. This is the key setting.
3. Notice the cogwheel icon beside that property. This opens the Cyber Code Configuration window. It allows you to define how the codes are generated.
You may select any of the default profiles here (and then press “Close”), or leave the window alone. Each profile has its own way of generating the codes; and you can create your own profile by toggling ON the “Advanced Mode”. But for now, we won't concern ourselves with its detail. Should you be ready to tweak the Configuration, you can read about it here.
4. Now the rest of the properties–on the Backtest Parameterization Panel–can be left to their defaults; or you can tweak them however you wish. Consult the help page for Backtest Parameterization Panel to understand each of those properties.
Don't forget to add the Fitness Functions according to your goals. We have a new metric called Total Trades/Cyber Code Expression Count which can be useful to reduce the occurrence of useless code (introns).
Next, add the Portfolio(s) of your strategy as usual. And make sure the System Settings properties are set to your liking–or you can leave them at default. Note, you can also parameterize any of the System Settings properties, as described here and here. Ditto the In Sample Periods (on the Backtest Panel) can be left at default, or set as described here.
5. Assuming you're creating strategies from scratch, the Buy Filters, Ranking, and Sell Filters panel are left empty. This way, all rules and filters are exclusively of the Cyber Code type. You can start the Divine Engine backtest right away by clicking the button “Start the Boss”.
A confirmation dialog shows up, telling you the estimated compute credit consumption for this backtest. Read more about this dialog here.
6. But if you decide to insert some built-in indicators, you can do so now before the Divine Engine backtest. Simply add the Buy, Rank, and/or Sell filters as usual.
Maybe you trust the RSI filter so much, and no trading strategy is complete without it, then add the RSI Filter. Or, you want to kickstart the evolutionary progression with the tried-and-true 200-day Simple Moving Average, then add the SMA Position Filter. Even if you add these built-in filters, the new rules added (and evolved) by the Divine Engine are solely of the Cyber Code type; the built-in ones will stay as you set them.
Now notice the leftmost parameter (flag) at those filters you added. These built-in rules can be set to Enabled, Disabled, or Random.
If you want a filter to stay no matter what, set it to Enabled. If you want the Divine Engine to decide whether a filter is useful or not, set it to Random. You can also parameterize their fields as you see fit, so the Divine Engine finds the best parameter values for them.
7. Now start the Divine Engine backtest by clicking the button as usual. Once finished, load any of the top strategies, one with good Fitness score (both IS and OOS), as the active strategy. Simply click the Load Parameters button from the Divine Engine Results Tab.
8. Notice the rules added by the Divine Engine are labelled as “Cyber Code Generator Rule/Filter”, whereas those built-in rules (those you added yourself) have their respective names displayed.
The Cyber Code buy and sell filters can't be manipulated by you; its parameters and values are “baked in” to the code itself. As for the Cyber Code Ranking Rules, you can still manipulate their “Highest/Lowest” parameter, as well as the Offset and Weight parameters; their code, however, can't be edited too.
Now to see the code contained in each rule, click the Curly Bracket icon. It shows you the pseudo-code–i.e. the simple, human readable format of the code–that drives the technical indicator. We'll discuss later how to decipher the code's workflow.
9. If you load a top strategy and decide to make a baseline from it (for further Divine Engine backtest), notice that the Cyber Code rules may have the flag “Replaceable/Not Replaceable” instead of the “Enabled/Disabled/Random” for the built-in rules.
A Cyber Code rule that's set to “Replaceable” may get replaced by a completely new rule, but the chance is quite low as otherwise the code in that rule doesn't have a chance to evolve. More likely, a “Replaceable” rule will stay, but some of its code have been evolved.
This section explains the mechanism (workflow) of the Cyber Code engine.
Each rule/filter is created by applying random blocks of code. These blocks can be found on the Cyber Code Configuration window (the Advanced Mode); look under the columns “Operation Type”.
In the beginning, a root block (root node) is created. Imagine an upside down tree: the root is the uppermost expression (operation) that produces the final result of the entire tree. The Cyber Code engine picks a random block for this root node, for example the Addition expression. This expression obviously has two operands (the two components that will be added); so from the root node, the tree branches in two. Thus the engine picks two more random blocks; for example Square Root and Division operations.
The Square Root has only one operand, so it does not branch; let's say it picks a constant or an input value to be square-rooted. When the engine picks a block like this, either a constant (for example a Pi 3.1416), or an input value (for example volume, closing, high, or low price), that is, a block that requires no operands, just a value, then this branch of the tree ends at this terminus. The Division branch though, requiring two operands, will branch further in two.
This process of branching and finding random blocks of code continues until the maximum “depth” of the tree is reached. In which case, the engine picks an input value as the terminus (the “leaves” of the tree). The flow of the code starts from the bottom (leaves) toward the root node at the top. Therefore constants and input values are always the building blocks of any Cyber Code rule; these are processed first and foremost. Note: The maximum depth of the tree can be set from the “Max Operation Chain Length”, in that Configuration window.
There are two types of trees: those for the Filters (Buy & Sell), and those for the Ranking Rules. The Filter trees yield a true or false value once they're fed the historic price data of a given instrument (the inputs and constants); so, true means it's a buy. Therefore the root node of such trees are always logical or relational operators; you can see such operators under the “Conditions” Operation Type on the Configuration window. As for the Ranking trees, they yield a number once they're fed the historic price data of an instrument. This number is then used to rank that instrument among other instruments.
All strategies in a population of 64, for example, are given these Cyber Code rules & filters. The standard evolution then applies: these strategies are backtested to find their metrics' values, and then tournaments are commenced to define the 32 survivors. After that, the usual cross-breeding: the two offspring strategies are given rules & filters picked randomly from the parents' rules & filters.
Now, comes the Cyber Code cross-breeding: a Cyber Code rule (from one Child) is randomly paired to another Cyber Code rule (from the sibling), and these two rules swap a node. If a rule doesn't find a pair, it'll be left alone as it is. One subtree (node) is exchanged for another subtree; it could even be the whole tree, or just a certain leaf (terminus). Which node gets picked is random, but the engine takes into account the “depth” of the two nodes, so they're of the same size, generally.
The property “Cross-Breeding Rate” defines the maximum depth of the node to be cross-bred. With a low rate, only the leaf/terminus is swapped, whereas a high rate may swap the entire tree. In summary, there are two levels of cross-breeding: first is the usual allocation of rules from the parents, and the second is the exchange of DNA codes between the rules. Note, it is also possible that two identical rules are crossbred; the diversity then comes from the different nodes each rule is swapping.
Once the offspring strategies are created, there's the usual mutation phase. But those Cyber Code rules are mutated differently: obviously, a Cyber Code rule doesn't have a customizable parameter. So its code (nodes) are the ones mutated. For every node in the tree, there's a percent chance it gets mutated. Of course, this chance is defined from the “Mutation Rate” property. When a node gets mutated, one of two things may happen:
Other “randomizable things” are mutated too, such as replacing an entire rule if it's flagged “Replaceable”, or any parameterized fields on a built-in rule you added yourself. But note, a Cyber Code rule has only a slight chance of getting replaced entirely, to avoid truncating the code's evolution prematurely.
Now that the offspring strategies are created through standard & Cyber Code cross-breeding, and standard & Cyber Code mutations, the standard tournaments are conducted again. These strategy-level tournaments hit two birds with one stone: not only they select the fittest strategies, but also the fittest Cyber Code rules (the fittest trees), as these rules are part and parcel of a given strategy. So there's no such thing as Cyber Code tournaments in which the rules battle each other out.
This whole process then repeats for the next generations until the evolution is finished. Thus, as you can see, with the Cyber Code evolution, not only the standard evolution is applied, but the code level cross-breeding and mutations as well. This allows for a more dynamic evolutionary progression to create the ultimate strategies.
Let's now learn how to translate the pseudocode into a tree diagram. This way, you'll get the gist of how the indicators work. Note that the Cyber Code engine is continually being improved, so things explained here may become obsolete and irrelevant. In this example, we have a ranking rule; click on the “curly brackets” icon to open the pseudocode:
To read this code, understand that the upper lines are usually the outer branches, containing the leaves. The root node is usually at the bottom. The computer executes the code from top to bottom, unless there's a “control flow” statement like “if” or a shared node. “var” indicates the declaration (creation) of a variable. “v0” is the name of that variable. Think of a variable as a container with a name. A variable may contain an expression, a mathematical operation, function, constant, input, or any code that needs to be contained. Note: Sometimes, a variable is declared without “var” preceding the name, but the data type associated with that variable, such as “double” or “bool”. “double” means the variable yields numerical value with decimal points, and “bool” means it's a variable that yields a true or false value (1 or 0).
In our case, the variable “v0” contains the function SUM, used for finding the sum total of the data sample. So let's draw a circle with a name “v0”, which contains the SUM function.
Now, a variable is usually a node that branches further. In this case, it is a node with two operands. The first operand is the “p.AdjustedClose”, that is, the adjusted closing price of an instrument. The second operand is the period of “121” days. These two operands branch out from the “v0” variable. As they are merely input & constant, they don't branch out more. Thus, they are the terminus (leaves). This “v0” subtree can be understood as “calculate the sum of all adjusted closing prices from the past 121 days”.
Now let's get to the second line. Here we have another function assigned to the variable “v0”.
It's common for a variable to have multiple assignments like this. That means, whenever the variable is called later down the line, it uses the latest assignment instead of the prior ones. The expression or function on the previous assignment has been calculated, as it is written earlier (above).
This next assignment of “v0” contains the function “Math.Max”, with two operands: “v0” of the previous assignment, and “p.AdjustedLow” signifying the current/today's adjusted low price of an instrument. Since the previous “v0” is the operand of the latest “v0”, we draw a line upward, connecting the previous circle into this new circle called “v0”. This circle contains the operation “Math.Max”.
Another branch of this circle, is the input value “p.AdjustedLow”. Thus, the new “v0” node tells the computer “find which operand has the greatest value: either the previous ‘v0′ (i.e. the sum of 121 days' worth of adjusted closing prices), or, the current adjusted low price of this instrument”. Let's say the “p.AdjustedLow” is the greatest, then this v0 node yields the value of “p.AdjustedLow”.
On the third line, we have a new variable declared, “v1”. It simply contains the subtraction operation between “p.Volume” (the amount of shares traded for a given day) and the Pi constant (3.1416). So let's draw a new circle called “v1” with the subtraction operation on it, with two operands: “p.Volume” on the left, and “π” on the right.
This subtree is still separated from the rest, as it doesn't contain any previously assigned variables (i.e. “v0”). It connects to the “v0” subtree on the fourth line.
Now, on this final line, usually we encounter “return”, indicating the root node, where the final value of the whole tree is calculated. “return” simply means this whole code/function/tree must “yield” or return a final value.
This root node contains the multiplication operation between “v0” and “v1”. Remember, the “v0” used here is the latest assigned, not the previous one. So we draw a line connecting the latest “v0” circle, to this root node, a circle that contains the operator “*” for multiplication. The “v1” circle is also connected toward this root node.
This root node is not a variable, so we don't put any label on the circle. The resulting number (product of multiplication) is then used to rank this instrument, in relation to the other instruments. Thus you get the general idea how the tree diagram is constructed.
Sometimes you may encounter logical or relational operators as shown in these code:
These are usually found on the Buy/Sell Filter trees, as they must yield a final true/false value (unlike the Ranking trees, which yield a number). In the first example, the node yields a true if the left operand is “greater than or equal” to the right operand; anything other than that yields a false.
In the second example, the node yields a true if both operands are true. As you see, the two operands are themselves nodes with relational operators, and if these nodes both yield true, the parent node yields a true; otherwise it's a false.
You may also encounter conditional statements like “if” or “?” :
In the first example, the expression after “if” (inside the parentheses) is used to define which path is taken: if the expression yields a true, then the statement after “if” (between the curly brackets) is executed, but if it's false, then the statement after “else” is executed. The second example is similar to “if”, but abbreviated. The expression before “?” defines which path is taken: if it yields a true, then the statement after “?” is executed; but if it's a false, then execute the statement after “:”. Usually, such a conditional statement is used to check/avoid division by zero.
When you draw the tree of a conditional statement you do it like this:
as if it's a node with three operands, albeit it's not an actual node signified by the dotted circle. Therefore the “if-then-else” circle and the conditional expression do not actually exist in the tree; they merely serve as a visual aid. The real node (subtree) comes from which path is actually taken (the latter two operands).
The same thing applies if there are nested conditional statements, like in this example here:
This is because the conditions merely define which path is taken. Each nested condition, taken individually, does not always alter the value itself; it may or it may not do so. So conditional statements, even if nested, do not increase the tree's depth.
There's also an “if” statement with “double.IsNaN( )” as shown in this pseudocode:
Such condition simply checks whether the variable inside the bracket yields a number. If it's a number, it returns false, and the “else” statement is executed (or if there's no “else” statement, the computer simply skips the “if” and continues to the next line). If it's not a number, it returns true, and the expression inside the “if” is executed.
In some cases, code bloat or “introns” are encountered. It's when the code don't make any sense (self-defeating, redundant, or inefficient). This is an inevitable side effect of the evolution's random nature. Our developers are continually finding ways to improve code efficiency and reduce such bloat.
Now we will explore thoroughly the Cyber Code Configuration window.
This window is used for configuring the way the codes are generated. Open this window by pressing the cogwheel button beside the “Rule Set Parameterization” property. Make sure you set that property to the option “Generate Cyber Code”.
When you first opened this window, the “easy mode” is displayed:
This mode simply lists all the profiles that you can load, either the “Default Profiles” (built-in profiles), or the custom profiles you saved before (under “My Saved Profiles”). Each profile contains its own settings on how the code will be generated. To load a profile, simply click it, and press “Close”. Now to get to the advanced mode, toggle ON the “Advanced Mode” (at the top-right corner). This mode allows you to create your own profiles, by manipulating the myriad controls there. Let us now explore each panel in this Advanced Mode:
1. Available Profiles – This panel lists all the profiles, similar to the “easy mode”.
Click on a profile to load it; and you'll see other panels have their settings changed. After you clicked a profile, press the “Close” button and it will be used to generate the code. Note, the active profile has its name displayed on top of this window:
Now, take note of the four buttons at the bottom-left of this window:
“New” lets you create a new profile. Click on that button, and a new profile is created under “My Saved Profile”. This profile (called “New Cyber Code Profile”) is automatically set with the default values. To rename this profile (or any profile under “My Saved Profile”), click its pencil icon and edit the name; once done, press Enter on your keyboard (or click the checkmark icon).
Since the new profile is created with the default settings, you may want to manipulate other panels as you see fit. Then, to save your customization, press the “Save” button. This “Save” button works on any profile you selected (under “My Saved Profile”); that is, any customization you made will be saved to that selected profile.
Note that profiles under “Default Profiles” can't be customized. You can copy them instead, so they're listed under “My Saved Profiles”. To do that, select a profile and press the button “Copy”. The duplicate has the suffix ” – Copy” on its name. So select that duplicate, manipulate its settings, and press the “Save” button. The same thing applies for profiles under “My Saved Profiles”.
Finally we have the “Delete” button, to remove a useless profile from “My Saved Profiles” (built-in profiles can't be deleted). Simply select a profile, click the “Delete” button, and press “Yes” on the confirmation dialog.
2. Cyber Code Generator Settings – This panel contains the general settings for the Cyber Code engine.
Max Operation Chain Length: This defines the maximum amount of vertical element (depth) in the tree. The resulting trees are capped at this depth; but it may be less than this. You can see in this tree diagram, it has a depth of 5, with each element highlighted. That is to say, each element is either a node or a terminus:
This is highly useful to limit the vertical growth of the trees, thus reducing code bloat and introns. The minimum value you can set here is 3, while the maximum is 50. A smaller value yields simpler trees, whereas larger values create more complex trees with many operations and data considered. Keep in mind, a large value not only increases Divine Engine backtest duration, but it may stop the evolution altogether as it exceeds computational memory (a warning will be shown to reduce this value).
Max Lookback: This affects the “Moving Values” and “Indicators” operation types, such as the EMA, RSI, Lookback, Standard Deviation S, and Sum:
It defines the maximum amount of days that these operations can look back. As you already know, for example, an Exponential Moving Average requires a certain amount of days (a period) to calculate its result. Such period may be less than what you set here, but never more. The longer the period, the more memory (RAM) will be used, thus the longer the Divine Engine backtest will be.
Constant Range: This defines the range that random numbers are generated from. “Random Number” is part of the “Constants” type:
Such random numbers are used in the mathematical expressions. When you edit this property, the right field must be greater than the left field, otherwise there's a warning. For example, a range of -10 to 10 means that the random number generated could be -10, -6, 1, 9, or even precise decimal value such as -9.76898975. Greater range means more variance in the random numbers used.
Shared Expression Reuse Pressure: This defines the likelihood that a “shared expression” is reused. A “shared expression” is a node with the variable name “se” (like “se0” and “se1”) that contains a mathematical expression. This node is “shared”, that is, it can be used by two or more nodes, by referencing it. That way, it serves to control the flow of the code; you can think of it as a node with multiple parent nodes.
Shared Condition Reuse Pressure: This defines how likely a “shared condition” is reused by other nodes. “Shared condition” is similar to “shared expression”, except it uses the variable “sc” (such as: “sc0” and “sc1”), and contains logical or relational expressions (that yields true or false) instead of mathematical expressions.
Rule Replacement Rate: This defines the percentage chance that a Cyber Code rule (the entire tree) gets replaced by a completely new tree during the mutation phase. The default value is 10%, and it's recommended to use such a low value. As stated earlier, the chance a Cyber Code rule gets replaced should be low, otherwise the code inside won't evolve properly.
3. Operation Weights – This panel contains the various code blocks (a.k.a. “operations”), that will be chained together to form the complex trees. Here you can define the likelihood that each block will be used in the trees.
Essentially, there are two columns here: the “Operation Type” (shown in red) contains the name of the blocks, whereas “Weight” (shown in green) defines the probability they will be used. Remember that each “Weight” stands in relation to the other “Weights”; so a value of 1 and 1 are considered similar to 100 and 100. But note, a value of 0 means the block will never be used.
The smallest weight you can input is 0, while the maximum weight is 99999.9.
Now, there are at least 9 types of block here:
Inputs: These are the historic data of a given instrument (from your portfolio); the “raw” data that will be fed to the tree. They denote the “current” data, that is, whatever date the backtest is currently processing. These blocks form the leaves or terminus of any tree.
Constants: Constants are simply fixed numbers (or a random number) used to modify a mathematical expression (for example, as a multiplier). Constants, just like the previously mentioned “inputs”, make up the leaves (terminus) of a tree.
Expressions: Standard Math: These blocks are the standard arithmetic operators. And as operators, they require operands; so they are nodes in the tree that branch further.
Expressions: Trigonometry: These are trigonometric functions, and they serve as nodes with their own operands.
Expressions: Moving Values: These are statistical functions, with a period of days as their sample range. As the name suggests, the period is a moving window. That is, the entire range is shifted one day forward if the previous day has been processed.
Indicators: These are technical trading indicators encapsulated as functions. These indicators are widely used as the foundation for other, more complex, modern indicators.
Conditions: These are logical and relational operators (and some functions that check a value). Each of them is essentially a condition, that will yield a true or false value (1 or 0), depending on whether the condition is met. They may be used as a conditional expression in “if” statements, or as individual expressions in their own right.
Expression Control Flow: These blocks control the flow of expressions (arithmetic operations, mathematical functions, etc) in the tree.
Condition Control Flow: These blocks control the flow of conditions in the tree (conditions as represented by logical and relational operators, or the boolean functions).
4. Additional Data Sources – This panel allows you to add exotic market data, as additional input to be considered by the Cyber Code engine (that is, in addition to the usual OHLCV data of your Portfolio).
Such exotic data are usually compiled by external sources. They serve like the usual inputs or constants in the pseudocode; each being a value (a percentage, for example) that can be used in any expressions. They're represented by the pseudocode “get(‘Data Source Name')”. For example, “get(‘ARKK Premium')” or “get(‘Bitcoin Trust Holdings/Share')”.
To add them, click the button “Add Data Source”. A dialog appears, allowing you to select the additional data. Once you ticked them, click “OK” and they're listed on this panel.
You can set their weights as usual (from 0 to 99,999.9), or delete them with their trash-bin icon. The date column (First Date), shows you the first time the data source (ETF) was traded on the exchanges; and this affects the strategy's backtest range (earliest date possible).
Currently, we have 173 data sources:
All of them (except the three highlighted above) are TAP Premium indicators. TAP stands for True Asset Price, and it shows you the true value (price) that a fund/ETF should be trading at. It's calculated by dividing all its net assets (i.e. minus the liabilities) by the number of shares in circulation.
Then comes the Premium (or Discount) part: most of the time, these ETFs are traded at a price higher (or lower) than their True Asset Price. If they're trading lower than the TAP (i.e. discounted), their price will likely go up. If they're trading higher (at premium), their price will go back down to their True Asset Price.
This discount/premium is calculated by dividing the ETF's adjusted closing price by its TAP, and this is subtracted by 1. The resulting number is a factor of 1 (as percentage) that shows how much of a premium (positive) or a discount (negative) that the ETF is trading at compared to its TAP.
These hundreds of ETF represent various indexes, asset classes, sectors, industries, and geopolitical regions. They range from corn to gold, Germany to China, futures and bonds, foreign currencies, cryptocurrencies, major indices, complex derivative indices, and even merger & acquisition index! All this to give you a unique edge on your strategy.
Now about the three data sources highlighted above (non TAP Premium data):
You may include these ETFs as part of the strategy's Portfolio, Cash Equivalent, or the filters' parameter, for a more direct effect to the strategy. Let's say you added SPY Premium, QQQ Premium, SH Premium, and PSQ Premium data sources:
You can then include SPY and QQQ on the strategy's Portfolio, while its Cash Equivalent is parameterized between SH or PSQ:
In other words, you may want to include the data sources related to your strategy's Portfolio. Use your creativity!
5. Additional Instruments – This panel allows you to add more market data to the Cyber Code engine, in addition to the usual OHLCV of the instruments (from your portfolio). But instead of exotic market indicators, you can add any instruments here (usually market indexes).
They're then taken as the usual inputs (the OHLCV data), with the ticker symbol preceding the input name. For example, instead of “p.AdjustedClose” it now says “SPX.AdjustedClose”.
To add an instrument, type its name or ticker symbol at the top-right field. From the dropdown that appears, select an instrument that matches your search. Or if you typed the ticker symbol correctly, simply press Enter on your keyboard. And the instrument is listed on this panel; you can then set its weight as usual, or delete it with the trash-bin icon.
The “First Date” column simply shows the earliest date for the instrument's historic price data.
Visual indicators are also available for Cyber Code rules. As usual, you can see them under the Instrument Tab. Make sure you click on an instrument first (from the Positions Tab) so the Instrument Tab is populated.
Here, the Cyber Code visual indicators appear on the 2nd section (the middle chart).
On the “Indicators” dropdown, you'll see which line (visual indicator) belongs to what rule. For example, “Ranking Rule #2” means the Cyber Code Ranking Rule located second from top at the Ranking Panel; “Buy Rule #1” means the topmost Buy Filter at the Buy Filters Panel, and so on.
This dropdown lists the Ranking Rules first, then below that the Buy Filters, and at the bottom cluster there are the Sell Filters.
Each Filter may contain more than one visual indicator, depending on how that filter works. To understand how it works, open its pseudocode viewer, and look at the variable referred to in the dropdown list. For example, “Sell Rule #1: Cyber Code (v1)” refers to the variable “v1” in the pseudocode. The values yielded by “v1” (the latest assigned “v1”) is plotted by this visual indicator.
Always remember that Buy and Sell Filters, no matter how complex the code is, ultimately yield a true or false value (buy or not buy, sell or not sell). So their root node must contain a relational or logical operator between the variables represented in the chart (if “v1” is higher than “v2”, for example, then it's a buy).
When it comes to Ranking Rules, they have only one visual indicator each. This indicator shows the final value (number) yielded by the entire tree, used for ranking the instrument, in relation to the other instruments. Keep in mind that higher value for the indicator does not necessarily mean it's ranked higher; take a look at the rule's “Highest/Lowest” parameter as well.
Note, if an indicator seems so flat throughout its history, either it's indeed flat (the value doesn't change), or because the scaling of the chart has been taken over by another indicator with huge values. If it's the latter case, simply disable that other indicator (from the dropdown).