Page History: Scripting Overview
Compare Page Revisions
Page Revision: 2011/08/01 22:25
Code Structure
Scripting code consists of one or more statements that are executed by the script interpreter.
Individual statements are separated by semicolons. White spaces (spaces, tabs, carriage returns, etc.) have no effect on how scripts are interpreted. Scripts are case-insensitive (e.g.
sma
is the same as
SMA
).
Statements can do the following:
- Perform a calculation.
- Assign a value or calculation to a variable name.
- Accept user input into a variable.
- Plot values on a chart in various different formats.
- Configure the chart.
Lets take a look at a script that computes the Disparity Index indicator:
VSCALE_DECIMALS(2);
periods = INPUT("MA Periods", 14, 1, 100);
indcolor = INPUT("Color", Color.Blue);
ma = SMA(CLOSE, periods);
di = 100 * ((CLOSE - ma) / ma);
PLOT_HISTOGRAM(di, 0.75, indcolor);
SUMMARY("Disparity Index({?}) {?:F2}", periods, di);
The first line,
VSCALE_DECIMALS(2);
, is a chart configuration command that states that we want numbers on the indicator value scale to display out to two decimal places.
Next, we accept some user input for the number of moving average periods and the color to draw the indicator. These values are stored in variable names (
periods
and
indcolor
) for later use in the script.
The indicator values are calculated next. This is done in two steps to make it easier to read and also to improve efficiency of the script. A simple moving average of the closing price is first computed and stored in variable
ma
. As you can see, we feed the user configurable number periods into the SMA function. This allows for the periods to be adjusted through the chart properties window without having to open and modify the script every time. Finally, we compute the disparity index as a percentage and store it in variable
di
. This is simply a computation of the percent difference of the current closing price to the moving average and the syntax was designed to be as intuitive as possible.
The last thing done by the script is to plot the values and display a summary.
This script produces the following output:
Also, because we used the input statement, the number of periods and the drawing color can be easily changed using the chart properties window:
Assign Values to Variables
Variables, in the scripting system, are simply names that hold values. Variable use is crucial to success in working with scripts. Not only do variables make scripts easier to read, they play a huge role in allowing scripts to run efficiently by not having to perform the same computation multiple times.
Take a look at the Disparity Index indicator one more again:
VSCALE_DECIMALS(2);
periods = INPUT("MA Periods", 14, 1, 100);
indcolor = INPUT("Color", Color.Blue);
ma = SMA(CLOSE, periods);
di = 100 * ((CLOSE - ma) / ma);
PLOT_HISTOGRAM(di, 0.75, indcolor);
SUMMARY("Disparity Index({?}) {?:F2}", periods, di);
If we didn't use the
ma
and
di
variables to store intermediate parts of our computation, here is what the script might look like:
VSCALE_DECIMALS(2);
periods = INPUT("MA Periods", 14, 1, 100);
indcolor = INPUT("Color", Color.Blue);
PLOT_HISTOGRAM(100 * ((CLOSE - SMA(CLOSE, periods)) / SMA(CLOSE, periods)), 0.75, indcolor);
SUMMARY("Disparity Index({?}) {?:F2}", periods, 100 * ((CLOSE - SMA(CLOSE, periods)) / SMA(CLOSE, periods)));
(Note: we still have to variables for INPUT statements because there is no other way).
This new script is perfectly valid and will run just fine, producing the same exact result as before. However, this script will run much slower because it is going to compute the same simple moving average 4 times, and the disparity index twice (once for the plot and once for the summary).
It goes without saying that you are going to want your scripts to evaluate as quickly as possible, especially in extremely busy markets where it could get executed many times per second.
Variables have an additional, slightly more obscure benefit as well. When you create a variable and assign it the result of a computation, you can think of the variable as representing a column in a spreadsheet...
Thinking of Scripts Like a Spreadsheet
A feature of the T4 chart scripting language is that if you can model your algorithm in a spreadsheet like Excel, then you should have no problems re-creating the same using the chart scripting language.
Think of rows in the spreadsheet as data points and columns as values of or at those data points (e.g. open, high, low, close, volume, etc.) When you create a variable and assign it a value, you are essentially creating a new column in the spreadsheet. You can then use column names as values in your equations, or plot the values of a column on the chart by passing the column name to a plotting function.
Spreadsheet rows represent data points. The base data points are the bars that get plotted on the chart. Each bar occurs at a specific time that depends on the charting interval being used (e.g. 15 minute, 1 day, etc.) Each data point also implicitly gets assigned an index value starting from 0 (for the first or latest bar).
When a script is executed, the interpreter starts at the first data point, or what would be the first row in the spreadsheet. The mathematical expressions are computed and the results get assigned to their respective values. Then the next data point (row) is evaluated and variables assigned values, and so on until every data point is evaluated and the spreadsheet is completely filled in.
Lets look at a simple example. The following script computes what is known as the Typical Price. This is simply the average of the open, high, and close prices of the bar.
x = (OPEN + HIGH + CLOSE) / 3
Our initial data looks as follows: (Note how we have created a column for the
x
variable in our script.)
Initial DataINDEX | DATE | OPEN | HIGH | LOW | CLOSE | VOLUME | x |
---|
0 | 06/01/2011 | 75100 | 76050 | 74100 | 75875 | 106528 | |
1 | 06/02/2011 | 75750 | 77000 | 75450 | 76650 | 81891 | |
2 | 06/03/2011 | 76550 | 76900 | 75100 | 75200 | 80819 | |
3 | 06/06/2011 | 75400 | 75800 | 73150 | 73175 | 82726 | |
4 | 06/07/2011 | 73200 | 73775 | 72925 | 73675 | 72927 | |
5 | 06/08/2011 | 73875 | 76650 | 73450 | 76275 | 113339 | |
6 | 06/09/2011 | 76400 | 79300 | 75950 | 78425 | 120824 | |
7 | 06/10/2011 | 78500 | 79975 | 77725 | 78575 | 86989 | |
The script has not executed yet, so we have the values of our data points which were loaded from the historical chart data servers, but the
x
column has not yet been computed.
The script interpreter will evaluate the data points one at a time starting with the first one at index 0.
Interpreter Evaluates the First Data PointINDEX | DATE | OPEN | HIGH | LOW | CLOSE | VOLUME | x |
---|
0 | 06/01/2011 | 75100 | 76050 | 74100 | 75875 | 106528 | 75675 |
1 | 06/02/2011 | 75750 | 77000 | 75450 | 76650 | 81891 | |
2 | 06/03/2011 | 76550 | 76900 | 75100 | 75200 | 80819 | |
3 | 06/06/2011 | 75400 | 75800 | 73150 | 73175 | 82726 | |
4 | 06/07/2011 | 73200 | 73775 | 72925 | 73675 | 72927 | |
5 | 06/08/2011 | 73875 | 76650 | 73450 | 76275 | 113339 | |
6 | 06/09/2011 | 76400 | 79300 | 75950 | 78425 | 120824 | |
7 | 06/10/2011 | 78500 | 79975 | 77725 | 78575 | 86989 | |
Then the next data point will be evaluated:
Interpreter Evaluates the SecondData PointINDEX | DATE | OPEN | HIGH | LOW | CLOSE | VOLUME | x |
---|
0 | 06/01/2011 | 75100 | 76050 | 74100 | 75875 | 106528 | 75675 |
1 | 06/02/2011 | 75750 | 77000 | 75450 | 76650 | 81891 | 76466.66666666667 |
2 | 06/03/2011 | 76550 | 76900 | 75100 | 75200 | 80819 | |
3 | 06/06/2011 | 75400 | 75800 | 73150 | 73175 | 82726 | |
4 | 06/07/2011 | 73200 | 73775 | 72925 | 73675 | 72927 | |
5 | 06/08/2011 | 73875 | 76650 | 73450 | 76275 | 113339 | |
6 | 06/09/2011 | 76400 | 79300 | 75950 | 78425 | 120824 | |
7 | 06/10/2011 | 78500 | 79975 | 77725 | 78575 | 86989 | |
Evaluation will continue until the last data point is computed.
You could get the same result by placing the data point values in a spreadsheet and assigning a cell in the first row the function
=(B2+C2+E2)/3
and then copy/pasting the cell formula down to every cell in the column.
Look Back Functions
Continuing with the spreadsheet analogy, we will now take a look at special functions that look back at past data point values.
Consider how a simple moving average is computed. A simple moving average is an average of the current value and some number of previous values. This is how it would look in a spreadsheet:
The chart scripting language includes a number a built-in functions that "look back" at previous values. The
SUM
function is one example.
SUM
takes two parameters: the value to compute the average of (this would be a column in the spreadsheet), and the number of periods, or rows, to add up.
We can use the
SUM
function to easily compute the simple moving average of, say, a closing price:
x = SUM(CLOSE, 3) / 3
In the script above, the interpreter will add the current close price and the previous two close prices. The formula then divides by 3 to get the average.
There are a number of additional built-in functions that look back at previous values, including a dedicated
SMA
function. These will be detailed in the function reference.
Offset Values
Similar to look back functions, your computation may call the the previous value of a data point. You can obtain this using field offsets. A field offset looks like this:
CLOSE[-1]
The square brackets tell the interpreter look retrieve the previous value (the -1) of the close price. You may use this, for instance, to compute the rate of change of something:
rocclose = (CLOSE - CLOSE[-12]) / CLOSE[-12];
Another way to accomplish the same thing is to use the
OFFSET
function. The
OFFSET
function take a value and a number of periods to look back. The difference between the
OFFSET
function and bracket notation is subtle. The bracket notation requires you to enter a fixed value, whereas the OFFSET function can take any value (constant, variable, etc).
Here is an example:
rocperiods = INPUT("ROC Periods", 12, 1, 1000);
rocclose = (CLOSE - OFFSET(CLOSE, -1 * rocperiods) / OFFSET(CLOSE, -1 * rocperiods);
In this example we wanted to make the ROC periods configurable so that we can tweak the study without having to edit the script. The
OFFSET
function can accept an expression that computes a value. The bracket notation would raise an error in this case.
Note that both the bracket notation and the
OFFSET
function take a negative value to look back. It is possible to use positive values to look forward as well if needed. An offset period of 0 would simply return the current value.
Compute SMA 3 Different Ways
Maybe this should go later.
Plotting Functions
There are a number of functions that will plot your computations on the chart. Some plots can be placed over the price bars (overlays) and some plots display in a separate panel above or below the price bar chart (indicators). Here is a summary of the available plot functions:
Plot FunctionsFunction | Overlay | Indicator | Example |
---|
PLOT_LINE | | | |
PLOT_STEP | | | |
PLOT_BANDS | | | |
PLOT_WAVECREST | | | |
PLOT_POINTS | | | |
PLOT_HISTOGRAM | | | |
All plot functions can be customized extensively. See the
Scripting Function Reference page for more information.
Plot Limit Lines, Center Lines and Range Markers¶
In addition to the standard plotting functions, there are a number of non-data based plotting functions for drawing reference lines on the chart. These functions are illustrated below.
There are many configurable options for plotting reference lines. Please the
Scripting Function Reference page for more details.
Display a Customized Summary
Format Tick Prices for Display
Change Plot Colors/Styles on the Fly
Custom Colors and Transparency¶
Accept Input via the Properties Window
Configure the Value Scale for Indicators
Using Aggregation Functions
Using IF Statements
Using the Cross Functions
Using NIL
Perform Recursive Calculations
Don't Reassign Variables
Don't Cause Circular References