ThinkScript
In this document you will find information on the thinkScript language. Using the price data in conjunction with functions, variables, and operators allows you to build up a whole system of your own studies and strategies. Being integrated into various features of the thinkorswim platform, thinkScript can be used for issuing alerts, scanning the market,
customizing quotes, and submitting orders automatically. The Getting Started section will help you get acquainted with
thinkScript and start writing your first scripts.
The Reference section provides you with information on constants, data types, declarations, functions, operators, and reserved words, explaining how to use them when writing scripts with thinkScript.
The thinkScript Integration section contains articles demonstrating usage of thinkScript integration features.
ThinkScript
•
Getting Started
4o Writing Your First Script 5
o Advanced Topics 19 •
Reference
35 o Reserved Words 37 o Declarations 68 o Functions 78 o Constants 256 o Data Types 312 o Operators 315 •
thinkScript Integration
324 o Conditional Orders 325 o Custom Quotes 327 o Study Alerts 329 o Study Filters 331Getting Started
This section contains tutorials that will help you get
acquainted with thinkscript and start writing your first scripts.
•
Getting Started
o Writing Your First Script 5
Defining Plots 5 Defining Variables 6 Def Variables 7 Rec Variables 8 Rec Enumerations 10 Using Functions 12 Formatting Plots 13
Adjusting Parameters Using Inputs 16
Accessing Data 17
Using Strategies 18
o Advanced Topics 19
Concatenating Strings 20
Creating Local Alerts 22
Referencing Data 23
Referencing Secondary Aggregation 24
Referencing Historical Data 27
Referencing Other Price Type Data 28
Referencing Other Studies 29
Referencing Other Symbol's Data 31
Past Offset 32
o
Writing Your First Script
This section contains tutorials that will help you write your first thinkscript study or strategy.
o
Defining Plots
In order to visualize data calculated by studies, you can use plots.
plot SMA = Average(close, 10);
This example script plots a 10 period simple moving average of the Close price.
When working with charts, you might need to use several plots. The following example script plots two moving averages of the Close price: the 10 period simple moving average and the 10 period exponential moving average.
plot SMA = Average(close, 10); plot EMA = ExpAverage(close, 10);
In case you only need one plot and don't need any inputs or intermediate variables, you can use short syntax:
Average(close, 10)
This example script plots a 10 period simple moving average of the Close price. Note that if you use the short syntax, your script must be a single expression.
o
Defining Variables
Thinkscript provides different types of variables to work with. This section contains tutorials that will teach you to work with these variables.
• Def Variables
7
• Rec Variables
8
Def Variables
The def reserved word defines a variable you'd like to work with. For example, you can define something called MyClosingPrice as:
def MyClosingPrice = Close;
By using the def reserved word, you can create a variable that can be used in another formula in the study. This let's you construct complex formulas from simpler elements. For example, if you want to divide the range of a stock price by the closing price, you can create a variable for the range:
def range = high - low; then create another variable: def percentrange = range / close;
Doing it this way lets you re-use variables and gives you the power to combine complex variables in your formulas more easily. By defining a variable such as:
def SMA = average(close, 20);
You can use that variable sma in your code as part of another calculation. For instance,
plot doubleSMA = SMA * 2; plot tripleSMA = SMA * 3;
Rec Variables
Rec variables are used to store floating point data. Values of such variables are calculated one after another in a chronological manner. When you assign a value to the rec variable you can use its values calculated for the previous bars. If you use data related to the period prior to the beginning of the time period then the rec variable is also calculated for the period. Before the calculation, the rec value is set to 0 for all moments of time.
rec x = x[1] + (random() - 0.5); plot RandomWalk = x;
Shows random walk. input drop = 5.0;
rec x = if close >= (1 - drop / 100) * x[1] then Max(close, x[1]) else close;
plot MaxPrice = x;
plot Drops = close < (1 - drop / 100) * x[1];
Drops.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ ARROW_UP);
In this example the rec variable holds the maximum close value starting from the moment of the last fall. When the price reduces on the defined percentage from the maximum, the maximum value resets.
declare lower;
rec x = x[1] + x[10] * 0 + 1; plot line = x;
This script takes data for the previous 10 bars. Thus, the rec calculation starts 10 bars prior to the beginning of the time period. As a result, the first drawn value of the plot line is 11.
declare lower; rec x = x[1] + 1; plot line = x;
Similarly, in this example the calculation starts 1 bar prior to the beginning of the time period. This is why the first visible value equals 2.
rec x = x[-1] + close; plot data = x;
This script refers to data that has not been calculated yet. Thus, it will produce an error. This applies to any
calculation of a rec variable which attempts to use its current or future value.
Rec Enumerations
You can use rec enumeration constructions to create something like a usual rec in thinkScript but with limited possible values.
Note that rec enumerations can contain only string values. rec a = {default neutral, up, down};
a = if (close == close[1]) then a.neutral else if (close > close[1]) then a.up else a.down;
plot q; switch(a) {
case up: q = low; case down: q = high; case neutral: q = close; }
The first line of the script is a declaration of a rec enumeration a having neutral, up, and down values. The default keyword indicates the default value of the rec enumeration. If you do not assign a value to a, it will always be equal to its default neutral value .
rec a = {default neutral, up, down};
The second line of this script is the assignment statement. Note that a rec enumeration can have only one assignment statement.
a = if (close == close[1]) then a.neutral else if (close > close[1]) then a.up else a.down;
The third line is just a plot declaration. plot q;
The rest of the script is a switch statement having the rec enumeration as a parameter. It is similar to the switch having an input enumeration as a parameter.
switch(a) {
case up: q = low; case down: q = high; case neutral: q = close; }
Note that rec enumerations are independent. This means that you cannot assign the same values to two different enumerations like in the following example.
rec a = {q, w, e, default r, t, y}; rec b = {q, w, e, default r, t, y}; rec c = {q, w, e, default r, t, y}; a = a.q;
b = a.q; ### error in this line c = a; ### error in this line plot z = 1;
Both sides of statements in the enumeration assignment should be of the same type:
rec a = {q, w, e, default r, t, y}; rec b = {q, w, e, default r, t, y}; a = a.q;
b = b.q;
plot z = a[1] == a.q;
plot x = a == z; ### error in this line plot y = a != if (1==2) then a else a.q;
plot w = if (1==2) then a else a.q != if (1==2) then b else b.q; ### error in this line
o
Using Functions
The thinkScript has a number of functions that can be performed on the price data to generate the desired study or strategy. For example,
plot CloseAvg = average(close, 12);
displays the average of the last 12 days' closing prices. Each function has required parameters. Average, for example, requires data (open, close, etc.) and length (number of bars). You can specify these parameters in any order. For example, plot SMA = average(data = close, length = 50);
and
plot SMA = average(length = 50, data = close); will show the same result on the chart.
o
Formatting Plots
The thinkscript contains lots of Look & Feel functions used to format a plot: define a plot type (histogram, line, point, etc.), color, line style and other.
Here is the common syntax for that:
<plot_name>.<L&F_function_name>(L&F_function_parameters )
In order to specify a plot type, use the SetPaintingStrategy function. Note that you can use this function only in combination with Painting Strategy constants. In case this function is not called, then the Line Painting Strategy is used. Note that plots from the following "signal" painting strategy category are drawn above plots from the common category:
• PaintingStrategy.ARROW_DOWN • PaintingStrategy.ARROW_UP • PaintingStrategy.POINTS • PaintingStrategy.BOOLEAN_ARROW_DOWN • PaintingStrategy.BOOLEAN_ARROW_UP • PaintingStrategy.BOOLEAN_POINTS • PaintingStrategy.DASHES • PaintingStrategy.HORIZONTAL • PaintingStrategy.SQUARES • PaintingStrategy.TRIANGLES
Plots defined first are drawn above plots defined later in the same painting strategy category.
declare lower;
plot AvgVolume = Average(volume, 7);
AvgVolume.SetPaintingStrategy(PaintingStrategy.HISTOGRAM );
In this example the average volume plot is represented by a histogram.
In order to define a plot line style and its width use the SetStyle and SetLineWeight functions. This function can only be used in combination with the curve style constants. Line width ranges from 1 to 5 pixels. If this function is not called, then a solid line with 1 pixel width is used.
plot SMA = Average(close, 10); SMA.SetStyle(Curve.LONG_DASH); SMA.SetLineWeight(3);
You can set plot color with the help of the SetDefaultColor, AssignValueColor, or AssignNormGradientColor functions. • SetDefaultColor is used to color the whole plot in a
specific color.
• AssignValueColor is used to color a plot in different colors depending on specified conditions.
• AssignNormGradientColor is used to color a plot in a gradient color depending on values.
In order to specify a color you can:
• Use Color constants, e.g, Color.RED.
• Use the Color function to reference named a plot color previously defined using defineColor
• Use the GetColor function. • Use the CreateColor function.
• Use the TakeValueColor function to reference color for anohter plot
Example
plot LowerBand = Lowest(low[1], 7); plot UpperBand = Highest(high[1], 7); plot Middle = (LowerBand + UpperBand) / 2;
Middle.DefineColor("Highest", Color.RED); Middle.DefineColor("Lowest", CreateColor(250, 150, 25)); LowerBand.SetDefaultColor(GetColor(5)); UpperBand.AssignValueColor(LowerBand.TakeValueColor()); Middle.AssignNormGradientColor(14, Middle.color("Highest"), Middle.color("Lowest"));
This example defined two named colors for the Middle plot. The "Highest" color is defined using a constant, "Lowest" is defined using the CreateColor function by defining the RGB components of the color. For the LowerBand the example uses a color from the dynamic color palette. The TakeValueColors function is used to indicate that the UpperBand should be colored in the same color as the LowerBand. The Middle plot will be colored in a gradient depending on 14 last bar values and colors selected for "Highest" and "Lowest". If you want to hide the a plot you can use the hide and setHiding functions. The setHiding function is diffenent from hide because it can hide/show a plot dynamically depending on certain conditions. plot SMA5 = Average(close, 5);
plot SMA10 = Average(close, 10); plot SMA15 = Average(close, 15); SMA10.hide();
SMA15.setHiding(getAggregationPeriod() < AggregationPeriod.DAY);
In this example the SMA10 plot is hidden by default and the SMA15 is hidden only on intraday charts by default. You can also hide the last plot value bubble and title in the status string with the current plot value using the HideBubble and HideTitle functions.
plot PastPrice = close[5]; PastPrice.HideBubble(); PastPrice.HideTitle();
o
Adjusting Parameters Using Inputs
Most studies and strategies are adjustable in terms of length, bounds or levels. You can create an adjustable parameter for your thinkScript study using the input reserved word. An input is like a def that can be adjusted in the Edit Studies and
Strategies window.
Example
input length = 12; input price = close;
plot SMA = average(data = price, length = length);
Here 12 and close are default values which you can override on the preferences panel the way you adjust any pre-defined studies.
o
Accessing Data
In order to access data from another symbol, data period, or price type in your code, append the name of the symbol in quotes and parentheses to the data type you want to use. Note that you can use the price type data for Forex symbols only. Example
plot data = close - close("GOOG");
The code will give you a line that is the difference between the closing price for the symbol that you have in the chart and the closing price for Google (GOOG).
For example on accessing another data periods or price types, see the open function desctiption in the Fundamental
o
Using Strategies
You can use thinkScript for fine-tuning pre-defined strategies or creating strategies of your own in the TOS Charts charting package. When strategies are drawn on a chart, Buy and Sell triggers appear in response to the conditions defined in the strategy. You can open a performance report by right clicking a signal and choosing "Show Report" from the pop-up menu in order to backtest selected strategies.
Note that currently you cannot send real orders using strategies.
You can add the following types of orders defined by the corresponding constants using addOrder function:
• BUY_AUTO
• BUY_TO_CLOSE
• SELL_AUTO
• SELL_TO_CLOSE
•
Note that to be able to close and open positions, you must add strategies with both buying and selling orders. After defining the order type, you should define a condition upon which the strategy should trigger. You can also specify trade price, number of contracts, and color of signals.
Example
addOrder(OrderType.BUY_AUTO, close < 50); addOrder(OrderType.SELL_TO_CLOSE, close > 70); This strategy comprises orders of both buying and selling sides. It adds a Buy (Entry) signal when the Close price drops below 50 and a Sell (Exit) trigger when the price exceeds 70.
o
Advanced Topics
This section contains tutorials that will help you write your first thinkscript study or strategy.
Here is a list of the tutorials: • Concatenating Strings • Creating Local Alerts • Referencing Data • Using Profiles
o
Concatenating Strings
You can concatenate two strings using the concat function. This may be useful when you want to pass the resulting string as a parameter to one of the following functions:
• AddChartLabel
• AddVerticalLine
• alert
• AddChartBubble
Note that the concat function preliminarily converts values of different types to a string. For this reason you can use any numeric values as the function's parameters.
Example 1
AddVerticalLine(getMonth() <> getMonth()[1], concat("Open: ", open));
This example draws a vertical line with the open value for the beginning of each month.
Example 2 (Concatenating more than two values) input price = close;
input threshold = 100;
alert(price > threshold, concat("Current price ", concat(price, concat(" is greater than ", threshold))), Alert.TICK);
This example defines a local alert that is triggered once a new quotation arrives in case the current price is higher that the specified price. In order to concatenate more than two values the example uses nested concat function calls:
Example 3 (Converting numerical value to a string) input isVerbose = yes;
AddChartLabel(yes, concat(if isVerbose then "Close: " else "", close));
This example draws a chart label and a note depending on the isVerbose parameter. As you can see from the example, in order to pass a numeric value as a string you need to preliminarily concatenate it with an empty string using the concat function:
o
Creating Local Alerts
In thinkscript you have the ability to create local alerts. In general, alerts are signals that are triggered when a condition is satisfied.
The common syntax for thinkscript alerts is the following: alert(condition, text, alert type, sound);
The condition parameter defines a condition on which you want this alert to be triggered. The text parameter places a specified text next to the alert. The alert type parameter defines a type of the alert.
Available alert type values are:
• Alert.ONCE – alert can be triggered only once after adding a study.
• Alert.BAR – alert can be triggered only once per bar. • Alert.TICK – alert can be triggered after each tick The sound parameter plays a sound when the alert is triggered.
Valid sound values are: • Sound.Bell • Sound.Chimes • Sound.Ding • Sound.NoSound • Sound.Ring Example
alert(open > 400, concat("Open is greater than 400! Current value is", open), alert.ONCE, Sound.Ring);
This example tiggers an alert when the open price becomes higher than 400. The alert is triggered once and it plays the ring sound.
o
Referencing Data
In this section you will find tutorials that describe ways of referencing data in the thinkscript.
Here is a list of the tutorials:
• Referencing Secondary Aggregation
24
• Referencing Historical Data
27
• Referencing Other Price Type Data
28
• Referencing Other Studies
29
• Referencing Other Symbol's Data
31
Referencing Secondary Aggregation
In order to access data of a different aggregation period in your code, specify the period parameter using the
corresponding Aggregation Period constant. You can also use a pre-defined string value for this purpose: 1 min, 2 min, 3 min, 4 min, 5 min, 10 min, 15 min, 20 min, 30 min, 1 hour, 2 hours, 4 hours, Day, 2 Days, 3 Days, 4 Days, Week, Month, Opt Exp, and <current period>.
Example
plot dailyOpen = open(period = AggregationPeriod.DAY); This code plots daily Open price for the current symbol. plot weeklyClose = close("IBM", period =
AggregationPeriod.WEEK);
This code plots weekly Close price for IBM. plot yesterdayHigh = High(period = AggregationPeriod.DAY)[1];
This code plots the High price reached on the previous day.
All indexers with such price functions use secondary aggregation period until you save it in some variable. Example
plot Data = Average(close(period = AggregationPeriod.DAY), 10);
This code returns a 10 day average of the Close price. However,
plot dailyClose = close(period = AggregationPeriod.DAY); plot Data = Average(dailyClose, 10);
will return an average of the Close price calculated for the last ten bars (the aggregation period used in calculation will depend on the current chart settings).
Note that two different secondary aggregation periods cannot be used within a single variable. In addition, the secondary aggregation period cannot be less than the primary aggregation period defined by chart settings. Example
plot Data = close(period = AggregationPeriod.MONTH) + close(period = AggregationPeriod.WEEK);
This code will not work on a daily chart. The correct script is:
def a = close(period = AggregationPeriod.MONTH); def b = close(period = AggregationPeriod.WEEK); plot Data = a + b; Example declare lower; input KPeriod = 10; input DPeriod = 10; input slowing_period = 3;
plot FullK = Average((close(period =
AggregationPeriod.WEEK) - Lowest(low(period = AggregationPeriod.WEEK), KPeriod)) / (Highest(high(period = AggregationPeriod.WEEK), KPeriod) - Lowest(low(period = AggregationPeriod.WEEK), KPeriod)) * 100, slowing_period);
plot FullD = Average(Average((close(period = AggregationPeriod.WEEK) - Lowest(low(period = AggregationPeriod.WEEK), KPeriod)) / (Highest(high(period = AggregationPeriod.WEEK), KPeriod) - Lowest(low(period = AggregationPeriod.WEEK), KPeriod)) * 100, slowing_period), DPeriod);
Example shows the Stochastic Full study using weekly price regardless of the current chart aggregation period. See the Stochastic Full for a detailed study description.
Referencing Historical Data
To access data in the past and in the future, you can use each of the two possible ways.
Indexing
Positive indexes are used to refer to data in the past and negative indexes to refer to data in the future. For
example, close[1] returns the Close price from one bar ago, close[2] returns the Close price 2 bars ago, etc. At the same time, close[-1] returns the Close price 1 bar forward, close[-2] returns the Close price 2 bars forward, etc. Example
plot momentum = close - close[5];
The example will plot a line that is the difference between the current Close price and the Close price 5 bars ago. Verbal Syntax
Verbal syntax allows using reserved human-readable sentences in the script. For example, close from 2 bars ago returns the Close price from two bars ago, close from 1 bar ago returns the Close price one bar ago, etc. Negative numbers refer to data in the future. For example, close from -1 bar ago returns the Close price one bar forward, low from -2 bars ago returns the Low price two bars forward, etc.
Example
plot scan = close from 4 bars ago + high from 1 bar ago; The example will plot a line that is the sum of the Close price 5 bars ago and the High price 1 bar ago.
Referencing Other Price Type Data
In order to access data from another price type in your code, put the priceType parameter with the name of the aggregation period in parentheses to the Fundamentals you want to use. Note that only Forex symbols support different price type data, all other symbols support only data based on the "LAST" price.
Example
plot ask = close(priceType = "ASK"); plot bid = close(priceType = "BID");
On the "MARK" price type chart for some Forex symbol this code will give you a ask and bid plots.
Referencing Other Studies
The thinkScript allows you to reference pre-defined studies or defined using the script reserved word in your code. Note that currently you cannot reference user-defined studies.
Example 1 (Using the reference reserved word) plot SMA = reference SimpleMovingAvg;
The code will plot a simple moving average with the default parameters of that study. For details see the reference reserved word article.
Example 2 (Referencing a pre-defined study with given parameters)
plot SMA = simplemovingavg(volume, 20);
This code will plot the 20 bar moving average of the volume. To see the input parameters of a particular study, click that study in the Edit Studies and Strategies window. You will see available parameters listed in the study properties section.
Example 3 (Referencing another plot in the embedded script)
script avg {
input length = 10;
plot SMA = Average(close, length); plot EMA = ExpAverage(close, length); }
declare lower;
plot SMAOsc = avg(10) - avg(20);
The code will produce two moving average oscillators in a separate subgraph. The SMA plot is omitted in the
reference because the first study plot is referenced by default. For details see the script reserved word article. Example 4 (Two ways of referencing studies with constant inputs)
declare lower; script study {
input direction = CrossingDirection.Any;
plot a = crosses(close, Average(close, 20), direction); }
plot test1 = Study("Above");
plot test2 = Study(CrossingDirection.Below); This script exemplifies two methods of referencing constant inputs of the embedded study. The first plot uses the short syntax ("Above"), while the second one uses the full syntax (CrossingDirection.Below) by specifying the full name of the CrossingDirection constant.
Referencing Other Symbol's Data
In order to access data from another symbol in your code, append the name of the symbol in quotes and parentheses to the Fundamentals you want to use.
Example
plot spread = close - close("GOOG");
The code will give you a line that is the difference between the closing price for the symbol that you have in the chart and the closing price for Google (GOOG).
Past Offset
When referencing historical data, one should mind a feature called past offset. Let us study the following example.
plot CloseOffset = close[5];
This example script will plot the Close price five bars prior to the current bar. This calculation mechanism is obvious for bars from the sixth through the last one, but how this plot will be calculated for the first five bars?
Past offset is a number of additional bars from the past, necessary for calculating a study. In this very example, past offset is equal to five; it means that calculation will start with the sixth bar using price data obtained from the first five bars. However, if additional historical data is available for the chart you are currently using, it will be used for calculating the plot for the first five bars. When writing a study, you might need to use several different past offsets for expressions in your script. Let us study the following example:
declare lower; rec x = x[1] + 1;
plot Average11 = Average(close, 11); plot myline = x;
In this example, variable x uses past offset equal to 1, while function average uses past offset equal to 10. In thinkScript, the highest past offset overrides lower offsets in the same study, which means that all expressions in a single study will have the same (highest) past offset. In the example script, this offset is equal to 10 and is assigned to both expressions. This is why the myline plot will return 11 for the first bar, not 2 as one might have expected.
Note that past offset might affect calculation mechanism of some studies due to setting a single intialization point for all expressions. However, if for some reason you need an independent initialization point for an expression, you can use the compoundValue function:
declare lower;
rec x = compoundValue(1, x[1]+1, 1);
plot ATR = average(TrueRange(high, close, low), 10); plot myline = x;
This would explicitly set the value for the myline plot for the first bar, and all the other values of this plot will be calculated corresponding to it.
o
Using Profiles
The TPO, Volume, and Monkey Bars profiles can be created in thinkScript using corresponding Profile functions. You can find the detailed description of these functions in the Profiles section.
In order to demonstrate the use of the functions, let's create a TPO profile study (colored blue) that aggregates all chart data on the right expansion.
Here is the code: def allchart = 0;
profile tpo = timeProfile("startnewprofile" = allchart); tpo.show("color" = Color.BLUE);
Reference
The reference describes thinkscript elements (functions, constants, declarations, etc.) required to create studies and strategies. The items are distributed alphabetically among the following sections: Constants, Declarations, Functions, and Reserved Words. Each article provides the syntax, description, and an example of use of the selected item.
All interrelated thinkscript items are cross-linked to ensure you have the fullest information about the relations inside the thinkscript.
Here is the list of the reference sections:
• Reserved Words
37
• Declarations 68 • Functions 78 • Constants 256 • Data Types312
• Operators315
•
Reference
o Reserved Words 37 o Declarations 68 o Functions 78 Fundamentals 79 Option Related 92 Technical Analysis 104 Mathematical and Trigonometrical 132
Statistical 156
Date and Time 170
Corporate Actions 185
Look and Feel 191
Profiles 220 Others 234 o Constants 256 Aggregation Period 257 Alert 268 ChartType 269 Color 273 CrossingDirection 283 Curve 285 Double 289 EarningTime 291 FundamentalType 293 OrderType 297 PaintingStrategy 299 PricePerRow 309 Sound 310 o Data Types 312 o Operators 315
o
Reserved Words
The thinkScript supports a number of simple commands such as for example: declare, plot, and input. These commands control the basic behavior of your thinkScript study. Choose your command from the list:
o
above
Syntax
See the crosses reserved word article. Description
The above reserved word is used with the crosses operator to test if a value gets higher than another value.
o
ago
Syntax
<value> from 1 bar ago
<value> from <length> bars ago Description
This reserved word is used to specify a time offset in a human-friendly syntax. For more information, see the Referencing Historical Data article.
o
and
Syntax
<condition1> and <condition2> Description
The and logical operator is used to define complex conditions. For a complex condition to be true it is required that each condition from it is true. In order to define the operator you can also use &&. This reserved word is also used to define an interval in the between expression.
Example
plot InsideBar = high <high[1] and low > low[1];
InsideBar.SetPaintingStrategy(PaintingStrategy.BOOLEAN _POINTS);
Draws a dot near each inside price bar.
o
bar
Syntax
<value> from 1 bar ago Description
This reserved word is used to specify a time offset in a human-friendly syntax. For more information, see the Referencing Historical Data article.
Note that bar and bars reserved words can be used interchangeably.
o
bars
Syntax
<value> from <length> bars ago Description
This reserved word is used to specify a time offset in a human-friendly syntax. For more information, see the Referencing Historical Data article.
Note that bar and bars reserved words can be used interchangeably.
o
below
Syntax
See the crosses reserved word article. Description
The below reserved word is used with the crosses operator to test if a value becomes less than another value.
o
between
Syntax
<parameter> between <value1> and <value2> Description
This reserved word is used in the between logical expression. It tests if the specified parameter is within the range of value1 and value2 (inclusive). The thinkscript also has the between function with a different syntax and usage.
Example declare lower;
def isIn = close between close[1] * 0.9 and close[1] * 1.1; plot isOut = !isIn;
In this example between is used to check whether the current closing price hits the 10% channel of the previous closing price. The isOut plot reflects the opposite condition.
o
case
Syntax
See the switch statement. Description
The reserved word is used in combination with the switch statement to define a condition.
o
crosses
Syntax
<value1> crosses above <value2> <value1> crosses below <value2> <value1> crosses <value2> Description
This reserved word is used as a human-readable version of the Crosses function. It tests if value1 gets higher or lower than value2.
Example
plot Avg = Average(close, 10);
plot ArrowUp = close crosses above Avg; plot ArrowDown = close crosses below Avg; plot Cross = close crosses Avg;
ArrowUp.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARR OW_UP); ArrowDown.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ ARROW_DOWN); Cross.SetPaintingStrategy(PaintingStrategy.BOOLEAN_POINTS );
This code plots up arrows indicating the bars at which the Close price gets higher than its 10 period average, and down arrows at which the Close price gets lower than its 10 period average.
The same result can be achieved by using the Crosses function: plot Avg = Average(close, 10);
plot ArrowUp = Crosses(close, Avg, CrossingDirection.Above); plot ArrowDown = Crosses(close, Avg,
CrossingDirection.Below);
plot Cross = Crosses(close, Avg, CrossingDirection.Any); ArrowUp.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARR OW_UP); ArrowDown.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ ARROW_DOWN); Cross.SetPaintingStrategy(PaintingStrategy.BOOLEAN_POINTS ); Example
plot Avg = Average(close, 10); plot Cross = close crosses Avg;
Cross.SetPaintingStrategy(PaintingStrategy.BOOLEAN_POINTS );
This code plots arrows indicating the bars at which the Close price gets higher or lower than its 10 period average. The equivalent code is:
plot Avg = Average(close, 10);
plot Cross = close crosses above Avg or close crosses below Avg;
Cross.SetPaintingStrategy(PaintingStrategy.BOOLEAN_POINTS );
o
declare
Syntax
declare <supported_declaration_name> Description
The declare keyword is a method for telling the chart
something basic about the appearance of the study or strategy you are creating. You can find the list of supported
declarations in the Declarations section. Example
declare lower;
plot PriceOsc = Average(close, 9) - Average(close, 18); The example shows how to use one of the most commonly used declations called lower. For other examples on declarations, see the Declarations section.
o
def
Syntax def <variable_name>=<expression>; or def <variable_name>; <variable_name>=<expression>; DescriptionDefines a variable you would like to work with. Example
def base = Average(close, 12); plot UpperBand = base * 1.1; plot LowerBand = base * 0.9;
This example shows a simplified SMAEnvelope study, where the def reserved word is used to define the base. The rational of defining this variable is to avoid double calculations (increase performance) in UppderBand and LowerBand plots, because def variable values are cached (by means of increasing memory usage).
You can separate the variable definition from its value assignment as shown in the following example where a variable value is assigned depending on the selected averageType input value.
See the Defining Variables section for more details. input averageType = {default SMA, EMA};
def base; switch (averageType) { case SMA: base = Average(close, 12); case EMA: base = ExpAverage(close, 12); }
plot UpperBand = base * 1.1; plot LowerBand = base * 0.9;
o
default
Syntax
See the enum rec, enum input, and switch statements. Description
The default reserved word is used in combination with the enum rec, enum input, and switch statements to specify a default value.
o
do
Syntax
def <result> = fold <index> = <start> to <end> with <variable> [ = <init> ] [ while <condition> ] do <expression>;
Description
This reserved word defines an action to be performed when calculating the fold function. For more information, see the fold reserved word article.
o
else
Syntax
See the if reserved word article. Description
The else reserved word is used to specify an additional condition in the if-expression and if-statement.
o
equals
Syntax equals Description
The reserved word is used as a logic operator to test equality of values. In order to define this operator you can also use the double equals sign ==.
Example
plot Doji = open equals close;
Doji.SetPaintingStrategy(PaintingStrategy.BOOLEAN_POINTS); The code draws points on bars having the Doji pattern (equal close and open).
o
fold
Syntax
def <result> = fold <index> = <start> to <end> with <variable> [ = <init> ] [ while <condition> ] do <expression>;
Description
The fold operator allows you to perform iterated calculations similarly to the for loop. It uses variable to store the result of the calculation. The initial value of variable is defined by init; if it is omitted, variable is initialized to zero.
The index is iterated from start (inclusive) to end (exclusive) with step 1. At each iteration, expression is calculated and assigned to variable. Value of index and previous value of variable can be used in expression. The value of variable after the last iteration is returned and can be used in assignments and expressions.
You can also specify a condition upon violation of which the loop is terminated.
Example 1 input n = 10;
plot factorial = fold index = 1 to n + 1 with p = 1 do p * index; Calculates the factorial of a number.
Example 2 input price = close; input length = 9;
plot SMA = (fold n = 0 to length with s do s + getValue(price, n, length - 1)) / length;
Calculates the simple moving average using fold. Example 3
plot NextHigh = fold i = 0 to 100 with price = Double.NaN while IsNaN(price) do if getValue(high, i) > 40 then getValue(high, -i) else Double.NaN;
Finds the next High price value greater than 40 among the following 100 bars.
o
from
Syntax
<value> from 1 bar ago
<value> from <length> bars ago Description
This reserved word is used to specify a time offset in a human-friendly syntax. For more information, see the Referencing Historical Data article.
o
if
Syntax (if-expression)
plot <plot_name> = if <condition> then <expression1>
else <expression2>;
plot <plot_name> = if <condition1> then <expression1> else if <condition2> then <expression2> else <expression3>; Syntax (if-statement) plot <plot_name>; if <condition> [then] { <plot_name> = <expression1>; } else { <plot_name> = <expression2>; } plot <plot_name>; if <condition1> [then] { <plot_name > = <expression1>; } else { if <condition2> [then] { <plot_name> = <expression2>; } else { <plot_name> = <expression3>; } } Description
As a reserved word, if is used in expressions and if-statements to specify a condition. If-expression always calculates both then and else branches, while if-statement calculates either of these, depending on the condition. In thinkScript, there is also if-function having syntax and usage different from those of the reserved word. The if-expression
can also be used in other functions such as, for example, AssignValueColor, AssignPriceColor, etc. Note that you can also use the def and rec instead of plot in the syntax provided above.
Example
input price = close; input long_average = yes;
plot SimpleAvg = Average(price, if long_average then 26 else 12); plot ExpAvg; if long_average { ExpAvg = ExpAverage(price, 26); } else { ExpAvg = ExpAverage(price, 12); }
In this example, if-expression and if-statement are used to control the length parameter of moving averages.
o
input
Most studies are adjustable in terms of length, bounds, or levels. You can create an adjustable parameter for your thinkScript study using the input reserved word. When defining inputs take the following notes into consideration:
• Inputs are displayed on the GUI in the same order as they appear in the source code.
• Inputs titles are always displayed on the GUI in the
lowercase. The following two definitions are similar on the GUI.
Code snippet 1
input test = "test in lowercase"; Code snippet 2
input TEST = "test in uppercase";
• Inputs can't have empty spaces in their definitions. The following code will result in compilation error.
input "input name with spaces" = "ERROR";
In order to have titles displayed on the GUI with spaces you can do one of the following:
Code snippet 3
input inputNameWithSpaces = "OK"; Code snippet 4
input input_name_with_spaces = "OK"; Find the full list of inputs in the following list:
• boolean • constant • enum • float • integer • price • string
boolean
Profile: Studies and Strategies Syntax
input <input name>=<boolean_value_used_by_default>; Description
Defines a boolean input. The default value of the input can either be "yes" or "no".
Example
input useHighLow = yes;
plot HighPrice = if useHighLow then Highest(high, 10) else Highest(close, 10);
plot LowPrice = if useHighLow then Lowest(low, 10) else Lowest(close, 10);
Draws the channel based on the highest and lowest price for the length equal to 10. Whether to use or not the high and low prices instead of the closing price can be defined using the correspondent input, which is set to "yes" by default.
constant
Profile: Studies and Strategies Syntax
input <input name>=<constant_used_by_default>; Description
Defines an input expressed by a constant of particular type. For the full list of supported constants, see the Constants section.
Note that color constants cannot be used for input definition.
Example
input secondaryPeriod = AggregationPeriod.DAY; plot SecondaryPeriodOpen = open(period = secondaryPeriod);
This example script draws the Open price plot with specified aggregation period.
enum
Profile: Studies and Strategies Syntax
input <input name>={default
<enum_value_used_by_default>, <enum_value_1>, ... <enum_value_N>};
Description
Defines an enum input of string values. In order to define the input it is required to:
• have all values specified in braces; • avoid equal values;
• have one value (not necessarily first) specified with the default reserved word which defines the default value for the input;
• place a value in double quotes if it contains a space symbol.
Example
input averageType = {default SMA, EMA, "Wilder's Average"}; plot Avg; switch (averageType) { case SMA: Avg = Average(close, 10); case EMA: Avg = ExpAverage(close, 10); case "Wilder's Average":
Avg = WildersAverage(close, 10); }
Draws the moving average based on the closing price with length equal to 10. The type of the moving average can be changed using the correspondent input, which is set to "SMA" by default. See other examples on inputs in the Fundamentals section.
float
Profile: Studies and Strategies Syntax
input <input name>=<float_number_used_by_default>; Description
Defines a float input. Note that in order to define this input you need to use a fullstop as a delimiter in its default value.
Example
input percentShift = 10.0;
plot UpperBand = close * (1 + percentShift / 100); plot LowerBand = close * (1 - percentShift / 100); Draws the envelope based on the closing price. The percent shift value can be adjusted using the correspondent input, which is set to 10.0 by default.
integer
Profile: Studies and Strategies Syntax
input <input name>=<integer_number_used_by_default>; Description
Defines an integer input. Example
input length = 10;
plot SMA = Average(close, length);
Draws the SMA using the close price data. The length value can be adjusted using the correspondent input, which is set to 10 by default
price
Profile: Studies and Strategies Syntax
input <input name>=<price_value_used_by_default>; Description
Defines a price input.
Valid parameters for the price type are: • open • high • low • close • hl2 • hlc3 • ohlc4 • volume Example
input price = close;
plot EMA = ExpAverage(price, 10);
Draws the EMA with the length equal to 10. The type of price data can be adjusted using the correspondent input, which is set to "close" by default.
string
Profile: Studies and Strategies Syntax
input <input name>="<string_value_used_by_default>"; Description
Defines a string input. Note that in order to have this input defined you need to specify double quotes in its default value.
Example
input symbol = "SPX";
plot Comparison = close(symbol);
Draws the comparison plot based on the closing price. The symbol for the comparison plot can be adjusted using the correspondent input, which is set to "SPX" by default.
o
no
Syntax no
Description
The no reserved word is used as a value for the boolean input or as the false condition. In order to define the false condition, you can also use the 0 value.
Example
plot Price = if no then high else low;
Since the condition is always false, the low plot is always displayed.
o
or
Syntax or
Description
The reserved word is used to define complex conditions. For a complex condition to be true it is required that at least one condition from it is true.
Example
input NumberOfBars = 3;
rec barsUp = if close > close[1] then barsUp[1] + 1 else 0; rec barsDown = if close < close[1] then barsDown[1] + 1 else 0; plot ConsecutiveBars = barsUp >= NumberOfBars or barsDown >= NumberOfBars;
ConsecutiveBars.SetPaintingStrategy(PaintingStrategy.BOOLE AN_POINTS);
This example highlights bars having the closing price lower than the closing price of the specified number of previous bars with a dot.
o
plot
Syntax plot <plot_name>=<expression>; or plot <plot_name>; <plot_name>=<expression>; DescriptionRenders the data you are working with on the chart. For more information about the reserved word, see the Formatting Plots tutorial.
Example
plot SMA = Average(close, 12);
This example draws a simple moving average study plot. You can separate the plot definition from its value assignment as shown in the following example where a plot value is assigned depending on the selected averageType input value. input averageType = {default SMA, EMA};
plot MA; switch (averageType) { case SMA: MA = Average(close, 12); case EMA: MA = ExpAverage(close, 12); }
o
profile
Syntax profile <variable_name>=<expression>; or profile <variable_name>; <variable_name>=<expression>; DescriptionDefines a profile to be displayed on the chart.
o
rec
Syntax rec
Description
Enables you to reference a historical value of a variable that you are calculating in the study or strategy itself. Rec is short for "recursion".
See the Defining Variables section for more details. Example
rec C = C[1] + volume; plot CumulativeVolume = C;
This example plots the cumulative volume starting from the beginning of the time period.
o
reference
Syntax
reference <StudyName>(parameter1=value1,.., parameterN=valueN).<PlotName>
Description
References a plot from another script. Note that the reference reserved word can be dropped but in this case parenthesis are necessary.
Full form:
plot MyMACD = reference MACDHistogram; Compressed form:
plot MyMACD = MACDHistogram();
The reference reserved work is required to distinguish the VWAP study from the vwap function, MoneyFlow study from the moneyflow function.
Calling the vwap function: plot MyVWAP1 = vwap; Referenicing the VWAP study: plot MyVWAP1 = reference VWAP;
If the plot name is not defined, study's main plot should be referenced (main is the first declared in the source code). If parameters values are not defined, default values should be used. Inputs' names can be dropped only for ThinkScript studies, because they have fixed order of inputs in the code: Full form:
plot MyBB2 = BollingerBandsSMA(price = open, displace = 0, length = 30);
Compact form:
Example
The following example references def and rec instead of the plot as shown at the top of the article.
def st = ATRTrailingStop().state; AssignPriceColor(if st == 1 then GetColor(1) else if st == 2 then GetColor(0) else Color.CURRENT);
def bs = !IsNaN(close) and ATRTrailingStop().BuySignal == yes;
def ss = !IsNaN(close) and ATRTrailingStop().SellSignal == yes; AddVerticalLine(bs or ss, if bs then "Buy!" else "Sell!", if bs then GetColor(0) else GetColor(1));
st is the reference to the state enum rec from the ATRTrailingStop study, bs and ss are references to the BuySignal and SellSignal def from the same study.
o
script
Syntax
script <script_name> { <script_code>; } Description
This reserved word is used to define new scripts you may need to reference later within a certain study or strategy.
Example script MyEMA { input data = close; input length = 12;
rec EMA = compoundValue(1, 2 / (length + 1) * data + (length - 1) / (length + 1) * EMA[1], Average(data, length)); plot MyEma = EMA;
}
declare lower;
plot Osc = MyEMA(close, 25) - MyEMA(close, 50);
This code defines the MyEma script where the first EMA value is calculated as SMA in contrast to the ExpAverage function whose first value is assigned the closing price. The main section of the code creates an oscillator based on the MyEMA difference for different lenghts.
o
switch
Syntax
plot <plot_name>;
switch (<enum input or enum_rec>) { case <enum value1>:
<plot_name> = <expression1>; ... default: <plot_name> = <expression>; } Description
The switch statement is used to control the flow of program execution via a multiway branch using the enum rec, and enum input. In the switch statement you either need to define the case with all values from the enum. Or you can use the default statement to define actions for all enums that are not defined using the case. Note that in this approach you cannot use case with equal enums.
Example
input price = close;
input plot_type = {default SMA, "Red EMA", "Green EMA", WMA}; plot Avg; switch (plot_type) { case SMA: Avg = Average(price); case WMA: Avg = wma(price); default: Avg = ExpAverage(price); } Avg.SetDefaultColor(
if plot_type == plot_type."Red EMA" then color.RED else if plot_type == plot_type."Green EMA" then color.GREEN else color.BLUE);
This example illustrates the usage of the switch reserved word to assign different values to plots. The default keyword must be used unless all possible values of variable are explicitly listed.
o
then
Syntax
See the if reserved word article. Description
The reserved word is used to specify an action to be performed when the if condition is satisfied. This reserved word is used only in combination with the if statement.
o
to
Syntax
def <result> = fold <index> = <start> to <end> with <variable> [ = <init> ] [ while <condition> ] do <expression>;
Description
The reserved word is used to define an interval to be used when calculating the fold function. For more information, see the fold reserved word article.
o
while
Syntax
def <result> = fold <index> = <start> to <end> with <variable> [ = <init> ] [ while <condition> ] do <expression>;
Description
This reserved word defines a condition upon violation of which the loop is terminated when calculating the fold function. For more information, see the fold reserved word article.
o
with
Syntax
def <result> = fold <index> = <start> to <end> with <variable> [ = <init> ] [ while <condition> ] do <expression>;
Description
The reserved word is used to define an iteration step value in the fold function. For more information, see the fold reserved word article.
o
yes
Syntax yes
Description
The yes reserved word is used as a value for the boolean input or as the true condition. In order to define the true condition, you can also use 1 or any non-zero number.
Example
input DisplayPlot = yes; plot Data = close;
Data.SetHiding(!DisplayPlot);
In this study, DisplayPlot input controls visibility of plot. Its default value is yes.
o
Declarations
Declarations are responsible for basic operations performed with charts such as changing the recalculation mode or setting the minimal chart value to zero. An important difference of declarations from other thinkscript items is that in order to define a declaration you need to use the declare reserved word.
The section contains the following declarations: • all_for_one • hide_on_daily • hide_on_intraday • lower • on_volume • once_per_bar • real_size • upper • weak_volume_dependency • zerobase
o
all_for_one
Syntax
declare all_for_one; Description
Keeps the volume value either in all price inputs or in none of them. This function is used to prevent visualizing irrelevant data in case the volume value does not combine with other price input values.
Example (Price Envelopes) declare all_for_one;
input HighPrice = high; input LowPrice = low;
plot UpperBand = Average(HighPrice) * 1.1; plot LowerBand = Average(LowPrice) * 0.9;
This example plots the high and low price envelopes at 10 percent above and below for the 12 day simple moving average. If you change the inputs to close and volume, the all_for_one declaration will automatically change the HighPrice and LowPrice inputs to the two volumes because the close and volume in combination lead to irrelevant data. As a result, the two volume values will be plotted.
Usage in:
o
hide_on_daily
Syntax
declare hide_on_daily; Description
Hides a study on charts with aggregation periods equal to or greater than 1 day.
Example
declare hide_on_daily; plot SMA = average(close);
SMA.AssignValueColor(GetColor(secondsFromTime(0) / 3600));
This study plots SMA of Close price and assigns a different color to the plot each hour. Due to declaration, this study will be hidden on daily charts.
o
hide_on_intraday
Syntax
declare hide_on_intraday; Description
Hides a study on intraday charts (time charts with aggregation period less than 1 day and tick charts).
Example (Implied Volatility) declare hide_on_intraday; declare lower;
plot ImpVol = IMP_VOLATILITY();
By definition, data for implied volatility is not available for intraday charts. Therefore, you can use the declaration to automatically hide studies on this type of charts.
Usage in:
o
lower
Syntax declare lower; Description
Places a study on the lower subgraph. This declaration is used when your study uses values that are considerably lower or higher than price history or volume values.
Example (Price Oscillator) declare lower;
input price = close; input fastLength = 9; input slowLength = 18;
plot PriceOsc = Average(price, fastLength) - Average(price, slowLength);
The example plots the difference between the two average values calculated on 9 and 18-bar intervals. The result value is lower compared to the price value. Therefore, it is reasonable to put the plot on the lower subgraph to avoid scaling the main chart.
Usage in:
o
on_volume
Syntax
declare on_volume; Description
Places a plot on the volume subgraph. General Information
By default, the application automatically defines where to place a study. If the study contains volume values and values not related to the base subgraph, then this study is displayed on the volume subgraph, otherwise it is displayed on the base subgraph.
However, it may be required to forcibly place the study on the volume subgraph regardless of the values you are using. Example (Volume Accumulation on the Volume Subgraph) declare on_volume;
plot VolumeAccumulation = (close - (high + low) / 2) * volume; The code in the example contains both volume and base subgraph related values. In order to place the study on the volume subgraph, the code uses the on_volume declaration. To study an example that uses only non-volume values, see the real_size function article.
Usage in:
o
once_per_bar
Syntax
declare once_per_bar; Description
Changes the recalculation mode of a study. By default, last study values are recalculated after each tick. If this declaration is applied, the study is forced to recalculate the last values only once per bar. This declaration can be used to reduce CPU usage for studies which do not need to be recalculated per each tick. Example
declare once_per_bar; input time = 0930;
AddVerticalLine(secondsFromTime(time)[1] < 0 && secondsFromTime(time) >= 0, concat("", time));
This study plots a verical line at the specified time point in EST time zone for each day. Since the time value is fixed, there is no need to recalculate the study after each tick.
o
real_size
Syntax
declare real_size; Description
Forces a study to use axis of either base subgraph or volume subgraph. Note that the axis of the volume subgraph can be used in case you use only volume values in your study. General Information
Studies always use the axis of the subgraph where you plot them except for the following two cases when the native plot axis are used:
• Study that is created for a separate subgraph (using the lower declaration) is moved to the base or volume subgraph using the On base subgraph check box; • Study that is placed on the base subgraph by default is
forcibly moved to the volume subgraph (using the on_volume declaration).
For the described two cases it may be required to use the axis of the volume or base subgraph, instead of the native plot axis. Example
declare real_size; declare on_volume; declare hide_on_intraday; plot Data = open_interest();
In the code above, in order to use the axis of the volume subgraph, you specify the real_size declaration.
Usage in:
o
upper
Syntax declare upper; Description
Enables you to place a study either on the base subgraph or on the volume subgraph. Note that a study is placed on the volume subgraph in case only volume values are used in the study. This declaration is applied by default to all studies not containing the lower and on_volume declarations.
Example (Price Oscillator) declare upper;
input price = close; input length = 9;
plot AvgWtd = wma(price, length);
In this example, the upper declaration places the weighted moving average plot on the main chart.
o
weak_volume_dependency
Syntax
declare weak_volume_dependency; Description
Places a study on the volume subgraph when at least one volume value is used.
Example (Keltner Channels) declare weak_volume_dependency; input factor = 1.5;
input length = 20; input price = close;
def shift = factor * AvgTrueRange(high, close, low, length); def average = Average(price, length);
plot Avg = average;
plot Upper_Band = average + shift; plot Lower_Band = average - shift;
Consider you are analyzing data that contains both volume and base subgraph related values using the code provided above. You want to display the plot on the base subgraph except for cases when you use at least one volume value. For the latter case, you would like to use the volume subgraph. In order to implement the logics, you use the weak_volume_declaration. If you use the close price input in the code, the study will be displayed on the base subgraph. If you use the volume price input, then there is a weak volume dependency and the study will be displayed on the volume subgraph.
Usage in:
o
zerobase
Syntax
declare zerobase; Description
Sets the minimal value on a study axis to zero if there are no negative values in the study.
Example (Price Oscillator) declare zerobase;
declare lower; plot Vol = Volume;
In this example, the Vol plot contains no negative values. It is reasonable to set the minimum value on the study axis to zero using the zerobase declaration.
Usage in:
o
Functions
Similar to functions in programming languages, each
thinkscript function receives input parameters and produces a result. In thinkscript the parameters can be specified in any order. For example plot SMA = average(data = close, length = 50) and plot SMA = average(length = 50, data = close) produce the same result.
All the functions are spread among the following sections:
• Fundamentals
79
• Option Related
92
• Technical Analysis
104
• Mathematical and Trigonometrical
132
• Statistical
156
• Date and Time
170
• Corporate Actions
185
• Look and Feel
191
• Profiles
220
o
Fundamentals
Trading analysis tightly relates to close, open, low, or high values. The thinkscript contains functions to work with these values. In addition, there are functions to work with data such as implied volatility, open interest, volume weighted average, and volume. All of them are collected in this section.
Here is the full list: • ask • bid • close • high • hl2 • hlc3 • imp_volatility • low • ohlc4 • open • open_interest • volume • vwap