What is a Study?

ChartIQ uses the term “study” to refer to any indicator, oscillator, average, or signal that results from technical analysis of chart data. The ChartIQ library performs this analysis by applying formulas to data stored in the chart object’s dataSet. The formulas exist, and results are calculated, within the library itself. This means that all computations are performed in the client’s browser.

A study, when added to the chart layout, may display its values either as an overlay on top of the chart, or in a separate panel adjacent to the chart.

When are Study Values Computed?

Study values are computed via a calculation function. This function stores the computed results in the chart’s dataSet. Once a study is added to the layout, the function is automatically called whenever the dataSet is recreated. The function can also be called manually to generate data in the dataSet; however, the data is lost the next time the dataSet is recreated.

As part of the animation loop, computed values are copied along with the quotes data from the dataSet to the dataSegment. Studies which are added to the layout will then render themselves based on their rendering function.

Built-in Studies

The ChartIQ library is packaged with over 100 studies. The code for these studies can be found in chartiq.js. Even more studies are available in the advanced package, in studiesAdvanced.js. For additional technical analysis theory and detail regarding some of the more popular built-in studies, please refer to the Built-in Studies reference site.

Custom Studies

Developers can customize the existing built-in studies, as well as create additional studies. Further on in this tutorial, there will be examples of how to accomplish this.

Using the Built-in Studies

Listing the Available Studies

The built-in studies are defined within the object CIQ.Studies.studyLibrary. To see a list of all studies in this object, iterate through it. In the following example, the names of the studies are output to the console, along with the study type. Some studies are purposely excluded. This filtering is useful if users are not to be provided with certain studies.

var arr=[];
var excludedStudies={
    "Directional": true,
for(var libraryEntry in CIQ.Studies.studyLibrary){
        arr.push(CIQ.Studies.studyLibrary[libraryEntry].name+": '"+libraryEntry+"'");

Here is the resulting partial output listing:

You may also obtain this in object form by calling the following function and examining the results: CIQ.Studies.getStudyList();

Adding a Study Instance to the Chart’s Layout

When an instance of a study is added to the chart’s layout, it becomes integrated within the chart. The library will perform all the future calculations and rendering automatically. The study instance will persist in the layout until it is removed.

An example of a built-in study is the RSI. The code below will put an instance of the RSI study in a panel at the bottom of the chart container and use the default settings (Period=14, Show 80/20 Zones, automatic color selection). The default settings were found in CIQ.Studies.studyLibrary["rsi"].

var sd=CIQ.Studies.addStudy(stxx,"rsi");

Note the function CIQ.Studies.addStudy returns an object called a study descriptor (sd). The study descriptor contains all the information necessary to create and persist a study instance. The study descriptor is what is stored in the layout for each study instance.

The study descriptor will be examined in more detail below.

Listing the Studies in the Layout

Any study descriptor added to the layout can be found in the stxx.layout.studies object. Iterate to see which studies have been added:

for(var studyInstanceName in stxx.layout.studies){
    var sd=stxx.layout.studies[studyInstanceName];

Iterating through the studies in the layout can be useful when creating a legend to display active studies to the user.

The Study Descriptor Object

Here is a screenshot in the debugger showing the rsi entry from the layout’s studies object.

Some of the more common properties of the study descriptor include:

Property Description
type The study’s key which was passed from the addStudy call.
name The unique name of the study instance. It is created by combining the type with the inputs. Unique names are necessary in order that multiple instances of the same study store their outputs separately. The name and the are set the same, and the name used as the key to the entry within the stxx.layout.studies object. If the type is present in the translations file, the name will be translated when using other languages.
inputs The values used to help perform the study calculations.

inputs.display - This reserved field is used to store a display-friendly name for the study instance. If not present, it is originally generated to be the same as It can also be modified at any time after the study is created. Note that it will not be translated to other languages when using CIQ.I18N.setLanguage
outputs The values which will be displayed by the study. Each value is assigned a color or an optional object that defines a customized line.
outputMap The fields in the dataSegment which will be read to retrieve the values used to render the study. These are automatically generated for each key in outputs by adding the study name. In rare cases, such as when outputs are to be found from quotefeed data, the outputMap will need to be programmatically adjusted.
panel The name of the panel in which the study will appear. The panel name, if not supplied when the study is added, will be the same as the study instance name.
parameters Additional values which help perform the study rendering.
study A reference to the study definition which was used to create this study instance. Usually, this is from CIQ.Studies.studyLibrary, but it can be supplied by the programmer as well. Once added to the study descriptor, it should not be modified (in legacy implementations, this was called libraryEntry, which is still included in the descriptor for backwards compatibility).
startFrom An index into the scrubbed array from where calculations for the study need to made. Any records prior to the one indexed will already contain calculated values.

Typical values within the study definition are discussed below.

The Study Definition

If a study descriptor represents an instance of a study, then a study definition would be its prototype. The study definition is an object which contains the default settings for a study,

Here is a typical study definition. It is for the “RAVI” study type, and it is a built-in study found within the CIQ.Studies.studyLibrary:

"RAVI": {
    "name": "RAVI",
    "seriesFN": CIQ.Studies.displayRAVI,
    "calculateFN": CIQ.Studies.calculatePriceOscillator,
    "inputs": {"Field":"field", "Moving Average Type":"vdma", "Short Cycle":7, "Long Cycle":65},"outputs": {"Increasing Bar":"#00DD00", "Decreasing Bar":"#FF0000"},
    "parameters": {
        init:{studyOverZonesEnabled:true, studyOverBoughtValue:3, studyOverBoughtColor:"auto", studyOverSoldValue:-3, studyOverSoldColor:"auto"}

Below are some of the more common properties of the study definition.

name – Full name of the study. Optional, this name can be used when referencing a study in a menu or in a dialog, for ease of understanding.

inputs – Default arguments passed into the study.

Inputs are used by the study to help compute its result.

The “inputs” field is not required, but if it is omitted, a default input of {"Period":14} will be created. This default exists since most studies utilize a period, and 14 is a typical setting. To force the study to have no inputs, set inputs to {}. An input can have any name as long as it is unique to the list of inputs, and does not use a reserved name (id, display).

An input can have one of the following value types:

  • Number (integer or decimal)
  • String
  • Boolean
  • Array of Strings

If the CIQ.Studies.DialogHelper object is used, there are a few shorthand values for inputs that can be utilized (as in the above example) to create an array of strings:

  • Literal “field” – will expand to an array of available fields in the dataset
  • Literal “ma” – will expand to an array of supported moving average types. Specifying a type of moving average (e.g., “vdma”) will do the same, but will default to the one specified. See “Adding a Moving Average Type” section below.

The unique id of a study instance is constructed using the inputs specified in this property.

calculateFN – Function which calculates the study results, also referred to as the “calculation function”.

This field is not strictly necessary, but omitting it indicates that the study does not perform any calculations because all resulting values are already present in the dataSet. This function will be discussed in more detail below.

outputs – Default colors and styles for each rendered study element.

*Set colors only

The colors can be expressed in either rgb, rgba, #hheexx or a web-friendly color name. Additionally, they can be set to “auto”, which allows the charting library itself to determine the appropriate color based on the chart theme. Outputs are not required, but if omitted, a default output of {"Result": "auto"} will be used.

"outputs": {"High":"#8cc176", "Low":"#b82c0c"}

*Set colors and styles

This feature is only available for line studies.

Two additional parameters are allowed along with color: width and pattern.

  • color is now it's own field. All the rules in the previous section still apply.
  • width takes a number and determines how thick the line will be displayed. Defaults to 1.
  • pattern is the line dash pattern that will be displayed and takes one of the following values: solid, dotted, dashed. Defaults to solid.
"outputs": {"High": {color:"#8cc176", width:3, pattern:"dashed"}, "Low":{color:"#b82c0c", width:4, pattern: "dotted"}}

Here is a screenshot showing the outputs as defined above.

parameters – Default additional fields affecting the study’s rendering.

Some studies support the specification of additional parameters. Any parameters specified within parameters.init will be copied into the study descriptor (sd.parameters) when the study is added.

The most common parameters supported deal with study zones for studies that render in a panel above or below the chart. A numerical value and color can be set for an over-bought and over-sold zone. The zones can also be enabled or disabled.

overlay – Whether the study will render over the chart or as a separate panel.

A value of true for this field indicates an overlay.

seriesFN – Function which renders the study results, also referred to as the “rendering function”.

Referencing a function here will allow a custom rendering of the study results on the chart. The results will appear either over the chart or in a separate panel, depending on the overlay property.

If this property is omitted, the results will be displayed as simple line plots, one for each field in the outputs property. If study zones are specified and overlay is not true, horizontal lines will be drawn at the zone levels and wherever results exceed the zone threshold the area between them will be shaded.

Note that the seriesFN function is called as part of the animation loop and should therefore be restricted to rendering computations. Any calculations of a study’s values which are dependent on quotefeed data should be put in the calculateFN function.

Convenience functions are available for the developer to use within seriesFN; they will be listed in a later section below.

Other properties are also available; they are listed in a table at the end of this tutorial.

The built-in study definitions can be found in chartiq.js. These files should not be modified directly. Instead, use CIQ.extend() function to add or modify entries to the studyLibrary.

Study IDs and Uniqueness

The library generates a unique ID for each study descriptor. This id is stored in its inputs object. No input should be given the name “id” for this reason.

The id property can be overwritten; however, care should be taken so that it is unique to any existing study instance’s id.

The panel name should also be unique for similar reasons.

Adding multiple study instances of the same type and input values will cause the study to display multiple times. While this is expected behavior, in order to ensure uniqueness, the generated, inputs.display and will have a sequence number appended to it. For example, the second "rsi (14)" study to be added will actually be named "rsi (14)-2".

Adding a Study Instance with Overriding Settings

Earlier, an RSI study was added to the layout using a simple call to CIQ.Studies.addStudy. In that case, the default inputs and outputs from the study definition were used to create the study instance. Usually, the defaults will need to be replaced with more desirable values.

To add a study while specifying different inputs/outputs than the defaults, simply pass in overrides to CIQ.Studies.addStudy. For example, here is the call to create the RSI with an Period of 20, with a yellow line chart, and without zones enabled:

var sd=CIQ.Studies.addStudy(stxx, "rsi", {"Period":20}, {"RSI":"yellow"}, {"studyOverZonesEnabled":false});

Similarly, we can add a 50 period exponential moving average with a blue line like so:

var inputs={"Period":50,"Field":"Close","Type":"ema"};
var outputs={"MA":"#0000FF"};
var sd=CIQ.Studies.addStudy(stxx, "ma", inputs, outputs);

It is possible to add an overlay study to any panel. Normally an overlay is assigned to the panel from which its “Field” input value belongs. If there is no Field input, the overlay is drawn on the chart's panel. To change the panel from this default, set the panelName argument of the addStudy function to the name of the panel that will be overlaid.

Here is an example of the Ichimoku Clouds study overlaid onto the Median Price study:

CIQ.Studies.addStudy(stxx,"Med Price");
CIQ.Studies.addStudy(stxx,"Ichimoku Clouds", null, null, null, "Med Price (14,n)");

Note that when passing inputs or outputs into addStudy, if null is not passed, the complete list of available fields must be provided. The library will not “merge” the fields with those provided in the study’s definition. Passing null will use the values from the study definition.

Replacing a Study Instance with Different Settings

Once a study instance has been created and added to the layout, it can be edited. In the example above, suppose the 20 period RSI now needs to have zones enabled at the 70/30 range. To do this, use the CIQ.Studies.replaceStudy function. The id of the existing study must be known.

var parameters={"studyOverZonesEnabled":true, "studyOverBoughtValue":70, "studyOverSoldValue":30};
var sd2=CIQ.Studies.replaceStudy(stxx,, sd.type, sd.inputs, sd.outputs, parameters);

As a result of this replacement, sd2 becomes the study instance which is in the layout. If the inputs have changed, a new id would be generated for the study. When replacing a study instance’s inputs or outputs using replaceStudy, be sure to pass all of the inputs or outputs, modified or not. Passing a null for inputs or outputs will cause the default values in the study definition to be used.

Changing the Default Settings of a Built-in Study

The study definitions in chartiq.js should not be edited directly. Instead, if a change is desired which will affect all instances of a built-in study, it should be made to the object by using CIQ.extend.

Here are some examples:

If you prefer default levels of 30-70 instead of 20-80 for overbought/oversold on the RSI study, do this:

CIQ.extend(CIQ.Studies.studyLibrary["rsi"],{parameters:{init:{studyOverBoughtValue:70, studyOverSoldValue:30}}});

If you would like the volume underlay to display as an overlay instead, do this:

CIQ.extend(CIQ.Studies.studyLibrary["vol undr"],{"underlay": null,"overlay": true});


  • Be sure to always reference the library entry key and not the study name. In the above, you can see we are using 'rsi' rather than 'RSI'; since that is how the library entry is defined:
    "rsi": {
      "name": "RSI",
      "inputs": {"Period":14},
      "calculateFN": CIQ.Studies.calculateRSI,
      "range": "0 to 100",
      "parameters": {
          init:{studyOverZonesEnabled:true, studyOverBoughtValue:80, studyOverBoughtColor:"auto", studyOverSoldValue:20, studyOverSoldColor:"auto"}
  • You must always redefine the study definitions before you import your layout or add any studies; otherwise the defaults will be used.

Adding Custom Studies

The ChartIQ library allows developers to create their own custom studies.

Adding an Ad-Hoc Study to the Layout

A study can be added to the layout even if it does not have a study definition. This is useful when creating simple studies based off data already found within the dataSet. For example, trueRange is a field found in the dataSet. To add it as a study, call:

CIQ.Studies.addStudy(stx, "tr", {"display":"True Range"}, {"trueRange":"green"}, null, "TRUE RANGE");

This will produce a panel with a green line plot of the true range. This only works because trueRange is already found in the dataSet by default. Note that “tr” is not a key to any defined study. The “display” input field set the value of the panel title seen below.

This method of adding a study is useful when data has already been calculated on the server and is passed to the client in the quote feed.

Creating a Study Definition

The “RAVI” built-in study definition was examined above. Using the supported properties for study definitions, custom definitions can be created.

Below is a custom definition for a “highlow” study, which just plots the high and the low as lines on the chart. This example will be expanded upon as the tutorial progresses.

var study={

This defines a study with no inputs. Since there is no seriesFN function, the outputs will be drawn as simple line charts. The output “High” will be green; “Low” will be red. The field “overlay” specifies this study as being drawn on the chart rather than in a separate panel. Since there is no calculateFN function, the dataSet is expected to already be populated with High and Low values. Indeed, studies can use raw values of whatever data is available in the quote feed to generate output.

If a calculateFN function is provided and a raw value in dataSet is to be used for output as well, the outputMap entry value for that field would need to be modified to map to the raw dataSet field name rather than the computed study output name.

Now that the study has been defined, it can be added to the study library as follows:


It can now be added to the chart like so:


The recommended approach to adding a custom study definition is to add it to the study library.

There is another way to use a custom study definition, without the study library. However, if it is not added to the library, its definition will need to be passed into addStudy and replaceStudy whenever they are used (see last parameter below):


The same rules governing supplying inputs and outputs apply here as well.

Studies that have been added to the layout may persist in the client’s local storage. If they are expected to be available and attached to the chart layout on page reload, the study definition must be available when re-importing the layout, since it is not stored anywhere permanent. Therefore, studies which do not have their definitions in the study library at import time will need to be updated with their study definitions. The below code, when run after importLayout, can aid in this:

function getStudyDefinition(type){
    // determine the right study for the type
return study;
for(var st in stxx.layout.studies){
    var imported=stxx.layout.studies[st];
    if(!CIQ.Studies.studyLibrary[imported.type]) CIQ.Studies.replaceStudy(stxx,, imported.type, imported.inputs, imported.outputs, imported.parameters, imported.panel, getStudyDefinition(imported.type));

Below is a screen shot of the resulting chart with the highlow study added.

The same custom study setup as above but with customized line outputs.

var study={
    outputs:{"High":{color:"green", width:3, pattern:"dotted"},"Low":{color:"red", width:4, pattern:"dotted"}},

The Calculation Function

The calculation function is responsible for inserting the study values into the dataSet. It is called every time createDataSet is called, which is whenever there is a change to the chart's data (e.g, when the quotefeed updates).

An example of a calculation function is the one used by the Typical Price study. The Typical Price at any point in time is the simple average of (High+Low+Close)/3 over N periods. Here is the calculation function for the calculateTypicalPrice function:

CIQ.Studies.calculateTypicalPrice=function(stx, sd){
    var quotes=sd.chart.scrubbed;
    var period=sd.days;
        if(!sd.overlay) sd.error=true;
    for(var p in sd.outputs){
        name=p + " " + name;
    var field="hlc/3";
    if(sd.type=="Med Price") field="hl/2";
    else if(sd.type=="Weighted Close") field="hlcc/4";

    var total=0;
    if(sd.startFrom<=period) sd.startFrom=0;
    for(var i=sd.startFrom;i<quotes.length;i++){
        if(i && quotes[i-1][name]) total=quotes[i-1][name]*period;
Calculation functions follow certain conventions.
  1. The function takes two parameters: The first is the chart instance. The second is the study descriptor. The calculation is free to add to or modify the study descriptor. In almost all cases the function will only need to access a few properties of the study descriptor:

    • days - same as the input "Period"
    • inputs - what is passed into the study
    • outputs - what result fields the function needs to calculate
    • name - unique name of the study instance
    • type - what type of study

    Here is a screenshot showing the properties of the study descriptor as it appears within the calculateTypicalPrice function.

  2. The raw values used in the calculation are taken from sd.chart.scrubbed. The data available in sd.chart.dataSet sometimes contains null values; sd.chart.scrubbed refers to the dataSet entries that are not null, so a good result can be obtained from the calculation. In almost all cases sd.chart.scrubbed should be used as the source data for the function.

  3. There are certain assumptions about what raw data is available for the calculation. By default, each record in sd.chart.scrubbed should contain any field supplied by the quotefeed, plus the following internally calculated fields:

    • iqPrevClose – this is the previous close
    • trueRange
    • atr – average true range with period=20
    • hl/2 – median price
    • hlc/3 – typical price
    • ohlc/4
    • hlcc/4 – weighted close

    For the Typical Price example, we are using hlc/3 to compute our result.

    It is important to note that studies should not expect results generated from other study instances to be present in the sd.chart.scrubbed array.

  4. Results are stored back into the sd.chart.scrubbed array. The naming convention used for the result in the array aims for uniqueness by appending the study name to the output field name. In this example, the entry would be “Result Typical Price (14, false)”.

    How this name is obtained is not immediately obvious. Since the study library did not specify any outputs, the sd.outputs object defaulted to {"Result": "auto"} as described in the previous section. The study name comes from, which was initialized to sd.type followed by the inputs in parentheses. Even though the inputs are listed in the debugger as first Overlay, then Period, the id is generated based on which field appeared first in the object when it was defined in the study definition. Hence, “Result” + “ ” + “Typical Price” + “ ” + “(14, false)”. Notice that this is the same as the outputMap field in the screenshot.

  5. Records stored in the sd.chart.scrubbed array do not need to be the final outputs of the study. Often (although not in this case) intermediate values are stored in sd.chart.scrubbed for a given data point so that future data points can reference it in the calculation. Only the values which are stored with field names corresponding to those in the outputMap will actually be drawn.

  6. The stxx.chart.createDataSet method will not clear any prior calculations of a study when quotes are updating. The createDataSet method will append the startFrom property to the study descriptor to give the calculation function a hint as to where in the scrubbed array the new records begin. In this way, it is possible for the calculation function to only compute results for new records added to to dataSet.

Important: note that startFrom is not an index for the dataSet and should only be used with the scrubbed aray.

Here is a screenshot of a record in the dataSet after the calculation function is run. Note the entry for the Typical Price.

The calculation function is assigned to the study definition as follows:

"Typical Price": {
    "name": "Typical Price",
    "calculateFN": CIQ.Studies.calculateTypicalPrice,
    "inputs": {"Period":14,"Overlay":false}

The Rendering Function

The rendering function is responsible for drawing the study values on the chart. It is called within the animation loop by the CIQ.ChartEngine.draw function. Therefore, whenever something changes on the chart (dataSegment), the rendering function is called.

Referring back to the “highlow” study example, note that this study does not have a rendering function defined. Therefore, its rendering function defaults to CIQ.Studies.displaySeriesAsLine. This function will plot the results (those values found in the dataSegment which correspond to outputs defined in the study) as lines either over the chart (as in the our highlow study) or in a separate panel. It will also draw study zones if applicable.

To not render anything from the study, set seriesFN to null.

To render a study in a different way on the chart, such as with a histogram, or as tick marks, a rendering function would need to be defined for the study. The rendering function takes three arguments: stx, sd, and quotes. The quotes argument is actually the same as sd.chart.dataSegment. The rendering function will need to access the sd.outputs, sd.parameters, and sometimes the study definition itself, stored in

There are several convenience functions that are available to perform some common rendering tasks on the canvas. Below is a sample rendering function for the Elder Force Index, which uses some available convenience functions:

CIQ.Studies.displayElderForce=function(stx, sd, quotes){
    CIQ.Studies.displaySeriesAsLine(stx, sd, quotes);
    CIQ.preparePeakValleyFill(stx,quotes,{panelName:sd.panel, band:"Result " +, threshold:0, direction:1, color:sd.outputs.Result});
    CIQ.preparePeakValleyFill(stx,quotes,{panelName:sd.panel, band:"Result " +, threshold:0, direction:-1, color:sd.outputs.Result});

In the function above, the first convenience function used is CIQ.Studies.displaySeriesAsLine. Then, CIQ.Studies.preparePeakValleyFill is called. This is a shading function; it fills in the area between the threshold line and the study result. It is called twice to shade both the area above and the area below the threshold (this is controlled by the direction parameter).

The resulting rendering is below:

Here is the rendering function for the MACD study, which draws a histogram along with the lines:

CIQ.Studies.displayHistogramWithSeries=function(stx, sd, quotes) {
    var panel=stx.panels[sd.panel];
    CIQ.Studies.createYAxis(stx, sd, quotes, panel);
    CIQ.Studies.createHistogram(stx, sd, quotes, false, 0.4);
    CIQ.Studies.displaySeriesAsLine(stx, sd, quotes);

Note the function CIQ.Studies.createYAxis. it needs to be called here first in order for both the histogram and the series lines to share the same axis.

A list of convenience functions for rendering studies can be found in the next section.

Sometimes the convenience functions are not adequate to render the study. In that case, the rendering function will need to access and draw on the canvas directly. To access the canvas rendering context, use stxx.chart.context. Use stxx.pixelFromBar() to get the x coordinates, and stxx.pixelFromPrice() to get the y coordinates of a data point on the canvas. From there, canvas API functions such as lineTo() and stroke() can be accessed to create the appropriate rendering.

To add a rendering function to a study definition, assign it to the seriesFN property:

"Elder Force": {
    "name": "Elder Force Index",
    "calculateFN": CIQ.Studies.calculateElderForce,
    "seriesFN": CIQ.Studies.displayElderForce,
    "inputs": {"Period":13}

Rendering Convenience Functions

Here are some common rendering convenience functions and their descriptions:

Function Description
CIQ.Studies.displaySeriesAsLine Each output field in the study is drawn as a line chart. If study zones were specified, those will be drawn as well.
CIQ.Studies.displaySeriesAsHistogram The outputs are displayed as histogram bars. The height percentage and width percentage of the bars are adjustable, as well as whether multiple output fields should show as stacked, clustered, or overlaying bars.
CIQ.Studies.drawHorizontal Draws a horizontal line on the chart at a given price.
CIQ.Studies.drawZones Draws the overbought/oversold levels and shades the area of the result which exceeds these thresholds. When zones are drawn, the y-axis does not display values; instead, it only displays the overbought/oversold levels. If a study output other than “Result” is to be applied to these zones, the output field must be specified by sd.zoneOutput.
CIQ.Studies.createHistogram Creates a histogram from a specific output from the study calculation. These outputs have the convention of ending with “_hist”. See function for details.
CIQ.Studies.displayHistogramWithSeries Draws a combination of CIQ.Studies.createHistogram and CIQ.Studies.displaySeriesAsLine.
CIQ.Studies.volumeChart Draws a special histogram which represents volume, having two different colors for the bars.
CIQ.Studies.displayChannel Draws a channel and fills in the area in between.
CIQ.fillArea Fills the polygon defined by an array of points with a semi-transparent color.
CIQ.prepareChannelFill Fills the area between two study outputs which form a channel. The output lines should not cross.
CIQ.preparePeakValleyFill Fills the area between a study extreme and the set threshold value, where the former exceeds the latter.
CIQ.fillIntersecting Fills the areas between two study outputs, with different colors depending on which of the outputs is greater.

In addition to the above, the function CIQ.Studies.displayError is automatically called for every study. This function will display a message on a panel study's panel whenever a study descriptor's error property is set. If set to true, the message "Not enough data to compute [study name]" will be shown; otherwise, a custom message can be displayed by setting the property to the actual message to be displayed.

Custom Initialization of a Study Instance

In most cases, when adding a study to the layout, no special initializations need to be done to get the study working. In some cases, however, a one-time setup may need to be performed whenever a study is first added or edited. For example, this may be done when loading supplemental data, enhancing or converting inputs/outputs, or performing special validations. A function in the study definition can be defined which will take care of any initial setup:

"initializeFN": function(stx, type, inputs, outputs, parameters, panelName){
    //your initialization here
    //The below should be called to perform default initialization
    return CIQ.Studies.initializeFN.apply(null, arguments);

The initializeFN function must return a study definition. It should call the default CIQ.Studies.initializeFN, which performs default initialization and returns a study definition.

The function is called automatically whenever a study is added or replaced in the layout.

Removing a Study Instance from the Layout

To remove a study from the layout, call:

CIQ.Studies.removeStudy(stxx, sd);

If sd is unknown, it can be accessed from stxx.layout.studies via the study instance id. Removing a panel study will also remove the panel in which the study appeared.

Sometimes it is necessary to perform a cleanup task when removing a study. For example, if a study in its initialization created a DOM element, removing the study ought to remove the DOM element as well. For this, a removeFN function can be set in the study definition. The removeFN function is called by CIQ.Studies.removeStudy automatically. A sample removeFN function may look like this:

    //removes a DOM element stored in the custom property studyDOMElement

Recalling the “highlow” study example, an initializeFN and removeFN function can be added to remove the candle chart plot, resulting in only the high and low plots being visible. Here is the modified study definition and chart.

var study={
        return CIQ.Studies.initializeFN.apply(this,arguments);

This definition sets the chart type to none on initialization and clears the chart type on removal, allowing the candles to reappear.

To remove all studies from the layout, iterate through the layout and then call removeStudy on each entry.

Simply setting stxx.layout.studies to null or an empty object is not advisable as no cleanup can be performed.

Performing a One-Time Study Calculation

Sometimes a calculation function will need an intermediate value that is the result of another study’s calculation. In this case, the calculation function will need to create a study descriptor for the study it needs and then calculate that study’s result. This will put the values required into the dataSet without adding the intermediate study to the layout.

For example, the Bollinger study calculation function depends on the Standard Deviation study and the Moving Average study calculations:

CIQ.Studies.calculateBollinger=function(stx, sd){
    var field=sd.inputs.Field;
    if(!field || field=="field") field="Close";

    CIQ.Studies.MA(sd.inputs["Moving Average Type"], sd.days, field, 0, "_MA", stx, sd);

    sd.std=new CIQ.Studies.StudyDescriptor(, "STD Dev", sd.panel);
    sd.std.inputs={"Field":field, "Standard Deviations":1, "Type":sd.inputs["Moving Average Type"]};
    sd.std.outputs={"_STD Dev":null};

    CIQ.Studies.calculateGenericEnvelope(stx, sd, sd.inputs["Standard Deviations"], "_MA ", "_STD Dev ";
    if(sd.type=="Boll %b") sd.zoneOutput="%b";

In this example, CIQ.Studies.MA is a convenience function for calculating the moving average. There is no convenience function for calculating the standard deviation, so the study descriptor std is manually created and stored in sd. The inputs and outputs are programmatically set and the study’s calculation function is invoked.

This method of creating a study without using CIQ.Studies.addStudy does not add the chart to the layout. As a result, each time the dataSet is recreated, the intermediate data is lost. Therefore, the calculation needs to be manually made each time the dataSet changes.

Note that utilizing a study in this way does not require there to be a study definition available. Everything the study will use is set in the descriptor.

Here is a screenshot of a data point in the sd.chart.scrubbed array after the calculateBollinger function has completed.

This study creates many intermediate entries that are not plotted. For the Bollinger Bands study, for example, only the three fields beginning with “Bollinger Bands” are actually plotted. Any other field containing the words “Bollinger Bands” are intermediate fields created by the calculation function to aid in the calculation of future values.

Adding a Moving Average Type

All the different types of moving averages (simple, exponential, etc.) share the same study definition. The moving average type is specified in an input field to the moving average study. When creating a new moving average it is desirable to have it available as a moving average type for other studies’ inputs. For this reason, adding a moving average type is somewhat more complex than adding a new study.

To see a list of all available moving average types (and their descriptive names), call:

var mas=CIQ.Studies.movingAverageHelper(stxx,"options");

Here is an example of creating a new moving average, the Geometric Mean. This mean is the Nth root of the product of the last N values.

The moving average object will first need to be extended to support this new average. Then a sub-calculation function will need to be written for this moving average. Each moving average type has a sub-calculation function which is called from CIQ.Studies.calculateMovingAverage, the main calculation function for the moving average study. Each sub-calculation needs to support the common moving average inputs of Period, Field, and Offset.

    conversions:{   // conversions: mapping of study type to moving average type name
    translations:{  // translations: mapping of moving average type name to display name
    typeMap:{       // typeMap: mapping of both study type and type name to calculation function suffix
                    // i.e., calculateMovingAverageXXX
        "gma": "Geometric", "geometric": "Geometric"

CIQ.Studies.calculateMovingAverageGeometric=function(stx, sd){
    var quotes=sd.chart.scrubbed;
    var field=sd.inputs.Field;
    if(!field || field=="field") field="Close";    // Handle when the default inputs are passed in
    var offset=parseInt(sd.inputs.Offset,10);
    if(isNaN(offset)) offset=0;
    for(var p in sd.outputs){
        name=p + " " + name;
    // find starting point in case of appending data
    var val;
    var offsetBack=offset;
    for(var i=sd.startFrom-1;i>=0;i--){
        if(!val && val!==0) continue;
        var quote=quotes[i];
        var notOverflowing=i+offset>=0 && i+offset<quotes.length;
        var offsetQuote=notOverflowing?quotes[i+offset]:null;
        if(!val && val!==0){
            if(offsetQuote) offsetQuote[name]=null;
        var base=1;
        var j;
            if(i<j) {
        if(offsetQuote) offsetQuote[name]=Math.pow(base,1/j);

At this point, any study which uses a moving average type as input can receive “gma” as the value. Interfaces which require the list of moving average types should be able to see the gma (geometric) MA in the results of CIQ.Studies.movingAverageHelper(stxx,"options").

Using a Moving Average in a Study

It is quite common for a study calculation to require a moving average as an intermediate value. Recall above in the calculateBollinger function, a moving average was required:

CIQ.Studies.MA(sd.inputs["Moving Average Type"], sd.days, field, 0, "_MA", stx, sd);

CIQ.Studies.MA is a convenience function that creates a study descriptor for a moving average and then calculates it, storing the result in the data set.

Adjusting the Position of a Study Panel

Study instances which are not overlays display themselves in their own panels. When one of these study instances is first added, the new panel for that study appears underneath the chart and any existing study panels.

The positions of the panels relative to each other can be adjusted programmatically.

The argument “panel” above is not the name of the panel, but the actual panel object (stxx.panels[sd.panel]).

The default height of the panel, in pixels, can also be set from within the study definition by setting the panelHeight property:


Removing a panel without removing the study to which it belongs is not advisable. Instead, use CIQ.Studies.removeStudy.

Controlling the Y Axis of a Study Panel

Control over the Y Axis parameters is possible via properties in the study definition. The following properties are available:

yAxis – use this property to extend the panel’s yAxis object. Any property of the axis can be accessed. Here is an example setting from the Volume Chart study:

"yAxis": {"ground":true, "initialMarginTop":0}

The "ground" parameter sets the zoom to only affect the top of the axis, leaving the bottom of the axis tied to 0. The "initialMarginTop" parameter sets the axis so that it extends to the very top of the panel with no gap.

yAxisFN – use this property to create a custom y-axis for the study panel. If the function is set, it will be called instead of CIQ.ChartEngine.createYAxis.

"yAxisFN": function(stx, sd){…}

range – This controls the minimum and maximum values of the y-axis. If omitted, the min and max are automatically calculated using CIQ.Studies.determineMinMax(), which finds the highest high and the lowest low to be displayed on the panel, and adjusts the axis accordingly so the entire plot can be viewed. The range property can be set to one of the following values:

  • "0 to 100"
  • "-1 to 1"
  • "0 to max"
  • "bypass"

Setting to “bypass” will allow manual setting of the min and max from within the calculation function. Access the study’s panel and set its min and max properties to the values desired:


The same effect can be achieved by setting sd.min and sd.max.

Here is an example of the use of yAxisFN. The yAxis will be replaced with a thick orange bar.

var study=CIQ.clone(CIQ.Studies.studyLibrary["Weighted Close"]);
        var panel=stx.panels[sd.panel];
        var ctx=stx.chart.context;
    initializeFN:function(stx, type, inputs){
        inputs.display="MY WC ("+inputs.Period+")";
        return CIQ.Studies.initializeFN.apply(this,arguments);
    name:"MY WC"
CIQ.Studies.addStudy(stxx, "WC", null, null, null, "WC", study);

Here is the resulting panel, between the “highlow” study from before and the default Weighted Close study. Notice the customized yAxis as a result of the modifications above.

Interacting with the UI

User interface functionality is available for the end user to add, edit, and remove studies and study panels. This section will address how a programmer can hook into this functionality at various levels.

Built-in Web Components

There are several web components within the library that can be used to help choose studies as well as edit and remove them:

  • StudyMenu – A scrollable list of all studies in the study library
  • StudyEdit – An edit dialog where a user can change inputs, outputs, and study zones
  • StudyLegend – A list of studies added to the layout. Each study in the list has a control to edit or remove the study

To control how these components display the studies, settings and configurations are available.

To exclude a study from being listed in the StudyMenu, set the params.excludedStudies object when creating the StudyMenu:

var params={
    excludedStudies: {
        "Directional": true,
var UIStudyMenu=new CIQ.UI.StudyMenu($("*[cq-studies]"), UIContext, params);

Normally when adding a study, it appears without showing the StudyEdit dialog. To force display of the dialog, set the params.alwaysDisplayDialog object for those studies you wish a dialog to appear:

var params={
    alwaysDisplayDialog: {
        "ma": true
var UIStudyMenu=new CIQ.UI.StudyMenu($("*[cq-studies]"), UIContext, params);

Note the params can be set directly upon the StudyMenu object:


Several properties in the study definition or study descriptor will affect web component behavior. These properties may also be used within a custom implementation of a study legend or edit dialog. If set in the study definition, they are applicable to all instances of the study. If set in the instance’s study descriptor, they are only applicable to the one instance of the study.

  • permanent – Set to true to make study non-removable. All controls to remove the study will be disabled.
  • edit – Set to false to disable editing of the study. All controls to edit the study will be disabled. To set this in the study descriptor, use sd.editFunction instead. There are special considerations that apply to this property; see “Customizing edit functionality” section below.
  • customLegend – Set to true to make study instance not appear in the StudyLegend.
  • deferUpdate – Set to true to make the study not update until the StudyEdit dialog is closed. This property is only available in the study definition.

The StudyLegend can be configured to only display studies which cannot be removed by highlighting the study. For example, a volume underlay cannot be highlighted. To indicate a study which cannot be removed by highlighting, and which will appear in this specially configured StudyLegend, set:


in the study definition.

Here is a screenshot of the StudyEdit built-in web-component:

The DialogHelper Object

CIQ.Studies.DialogHelper is a class that reads all inputs, outputs, and parameters in the study definition, and creates structures that make creating an edit dialog simple and straightforward. It creates objects for each input, output and parameter that can be used to render controls on an edit dialog.

The DialogHelper constructor performs the following actions -

  • For each input field:

    • If the input value is a number, input validation parameters are assigned, if applicable (see Input validation section below).
    • If the input is Boolean, an object is created emulating a checkbox.
    • If the input value is an array, an object is created which has the properties of a select dropdown (options, etc.).
    • If the input value is a moving average abbreviation, an array is created which contains each moving average type. An object is created which has the properties of a select dropdown. The default field is “ma”.
    • If the input value is “field”, an array is created which contains each field in the data set that the study can conceivably use as input. It will not display itself, or a study which uses itself as its field (that would create a circular dependency). An object is created which has the properties of a select dropdown. The default field is “Close”.
    • Sets a default property for each input. The default comes from the study definition, unless the input is passed to the DialogHelper class constructor.

  • For each output field:

    • Sets the value from the study definition, unless the output is passed to the DialogHelper class constructor.

  • For the study zones:

    • Reads the values from the parameters.init object in the study definition.
    • Sets input validation rules on the numeric values.
    • Overrides these with parameters passed to the DialogHelper class constructor, if applicable.
    • Creates three objects; one for the Show Zones flag, one for the overbought level and color, and one for the oversold level and color.

Using the inputs, outputs and parameters properties of the DialogHelper, it becomes much more straightforward to construct an edit dialog.

To update the DialogHelper object, use its updateStudy method. This method accepts an object containing those inputs, outputs, or parameters which have changed, and will update the DialogHelper properties accordingly.

Below is an example of using the DialogHelper object to first create a moving average, then modify it.

var dialogHelper = new CIQ.Studies.DialogHelper({"stx":stxx,"name":"ma"});

// Here you would gather user input to customize the MA, to a period 5 and green line.
// When the user is done, call updateStudy:


Input Validation

In order to control what inputs are being sent into the study, input validation should be performed. When using the built-in study dialog component, input validation is performed automatically on all numeric input fields by comparing the value supplied by the user with the default value of the input from the study definition. The user is not allowed to proceed with the edit unless the input is validated.

Validation can be customized for a particular numeric input or parameter field by setting the “attributes” property in the study definition for the study. The value of the attributes property is an object that contains keys (input field names) and values (validation parameters).

    field1: validation1,
    field2: validation2,

Supported validation parameters include:

  • step: Input must be a multiple of this value. Omitting will default to 1 for integer defaults and .01 for decimal defaults
  • min: Lowest value allowed
  • max: Highest value allowed
  • readonly: (all input types) If "readonly", value will not be editable
  • hidden: (all input types) If true, both field name and value will be hidden More parameters may be added but they will not be supported by the built-in study dialog.

Here is an example of a validation setting:

    "Factor": {step:0.05, min:3, max:10},
    "Period": {readonly:"readonly"},
    "Type":        {hidden:true}

This setting will restrict user-entry for the Factor field to numbers between 3 and 10, divisible by .05. The built-in edit dialog accomplishes the validation by setting the HTML attributes of a number-type input box. It will make the Period field read-only, and the Type field will not show at all on the dialog.

Omitting a validation parameter should effect the following validation:

  • step: 1 or .01, depending on whether the default input value was an integer or a decimal
  • min: no minimum
  • max: no maximum
  • readonly: editable
  • hidden: visible

When not specifying validation for a field, the following should apply:

  • step: 1 or .01, depending on whether the default input value was an integer or a decimal
  • min: 1 if default input value was a positive integer, .01 if positive decimal, otherwise no minimum
  • max: no maximum
  • readonly: editable
  • hidden: visible

When using the DialogHelper, any fields not already assigned validation attributes are automatically assigned them according to the rules above. If not using the DialogHelper, the rules above provide guidelines as to how to set validation. If there is no study definition, there will be no input validation.

Example: "Offset" field has a default of 3. The default validation would restrict the field to positive integers. To set the field to allow negative values as well, set the attributes object like so:

"attributes":{ "Offset":{} }

When the built-in edit dialog is not being used, input validation can be performed programmatically within the editFunction or edit callback. Note that some of the built-in studies have the attributes set already, so these would need to be taken into account. The attributes are accessed from the study descriptor like so:[fieldToValidate];

Customizing Edit Functionality

When a study is added to the layout, the study descriptor receives an edit function (sd.editFunction) that would be called whenever an edit of the study is requested. An edit is requested when:

  • An overlay plot is hovered over and highlighted, and the edit option selected
  • A panel study’s edit control is pressed
  • A StudyLegend item is selected
  • The sd.editFunction is directly invoked

By default, when one of these actions occurs, optional callback functions are executed. If the built-in web components are being used, callback functions are already set up to open a study edit dialog. If these components are not being used, the callbacks should be defined in order to perform any action when the user triggers an edit. To add callbacks, use the stxx.addEventListener function:

//params={stx:stxx, inputs:sd.inputs, outputs:sd.outputs, parameters:sd.parameters}
stxx.addEventListener("studyOverlayEdit", function(params){…});   //for overlay studies
stxx.addEventListener("studyPanelEdit", function(params){…});   //for panel studies

To remove them, use the stxx.removeEventListener function.

There are separate callbacks for overlays and panel studies because overlay studies may require a context menu to choose an action, whereas panel studies usually have dedicated controls for different actions.

It is important to note that these callbacks need to be defined very early in the CIQ initialization process, namely, before importing the layout. If this is not done early enough, the callbacks will not apply to those studies being imported.

It is possible to override the callback edit functionality on a per-study basis by adding an “edit” property to the study definition. As discussed earlier, this property can be set to false to disable editing completely. It can also be set to a function to handle it. The function takes the following form:

//params={stx:stxx, inputs:sd.inputs, outputs:sd.outputs, parameters:sd.parameters}

The following edit function, when added to the RSI study definition, will change the line color when an edit is triggered on an instance of it:

    var colors=["red","blue","green","yellow"];
    CIQ.Studies.replaceStudy(params.stx,, sd.type, params.inputs, params.outputs, params.parameters);

When an RSI instance is created, this function is copied to the study descriptor as sd.editFunction instead of the appropriate callback function.

Here is an example which increments the period:

    CIQ.Studies.replaceStudy(params.stx,, sd.type, params.inputs, params.outputs, params.parameters);

CIQ.Studies.replaceStudy should be called whenever changing anything that affects the study descriptor (inputs, outputs, etc.). This is done to make sure the study descriptor id, display and panelName properties are all properly updated.

The above examples are simplistic and only scratch the surface of what can be done with the edit function. A more complex edit function would pass the params into some sort of mechanism to manage the edit.

Customizing Overlay Highlighting

Overlay studies, when hovered over, become “highlighted”. Highlighted overlays appear as 3-pixel wide lines if the built-in rendering functions are used. A highlighted study has the highlight property set to true in the study descriptor. The edit callbacks are only executed if this property is set.

By default, only overlays that are rendered as lines change appearance when hovering over them. Other built-in rendering functions do not set the highlight property to true. However, custom rendering functions can change the appearance of the overlay when the highlight property is set. In addition, one can define a highlighting function for any overlay, which will set the highlight property given the mouse position (or other criteria).

To override the highlighting functionality for any study, place into the study definition:

"isHighlighted":function(stx,cx,cy){   //arguments are the chart object, x mouse coord, y mouse coord
    //test mouse coord against data points using pixelFromBar and pixelFromPrice
    if(…) return true;   //highlighting should occur
    else return false;

To disable highlighting altogether, just set to false:


To summarize, set sd.highlight=true when the edit option should be presented to the user. This is customarily set when a user hovers over a study plot. By default this functionality works only for line studies. It can be defined differently for each study by setting the isHighlighted function in the study definition.

Here is an example of the isHighlighted function as applied to the “highlow” study from before. Instead of highlighting when the mouse hovers above one of the lines, now the highlighting will instead appear when the mouse is within 20 pixels of the left of the chart.

var study={
        return CIQ.Studies.initializeFN.apply(this,arguments);
        return cx-stx.chart.left<20;

Other Settings

Below are some more settings available in the study definition.

  • appendDisplaySeriesAsLine – a function which acts as an injection for the displaySeriesAsLine function.
    • It will be called using the following signature: appendDisplaySeriesAsLine(stx, sd, quotes, name, panel);
    • stx : The chart object
    • sd : The study descriptor
    • name : The name of this study instance (should match field from 'quotes' needed to render this line)
    • quotes : The array of quotes (dataSegment)
    • panel : A reference to the study panel
  • centerline – set to a value and a horizontal line will be drawn in the study panel at that level.
  • display – set to a custom display name for the panel. Note that this should only be set on studies which do not accept inputs, as otherwise the display name will not be descriptive enough to distinguish between different panels of the same study.
  • feed - optional data feed to be used in addition to the attached quote feed.
  • horizontalCrosshairFieldFN – set to a function which returns a field name. When hovering over the study panel, crosshairs will snap onto that field’s value.
  • underlay – set to true in lieu of overlay. Underlays render like overlays except they appear behind the chart rendering (e.g., behind the candles)

Reference Table of Study Definition Settings

Property Purpose
appendDisplaySeriesAsLine Function which is executed after displaySeriesAsLine rendering function
attributes Input validation object
calculateFN Calculates study result values
centerline Draws a horizontal line in a panel at the value specified
customLegend Indicates whether study appears in the web component study legend
customRemoval Indicates a need to supply removal function for overlay in lieu of context highlight removal
deferUpdate Delay updating of study until edit dialog is closed
display Name to show on the panel and in study legends (for study with no inputs only)
edit Function to either disable or control editing of a study
feed Specify an alternate quote feed used by the study
horizontalCrosshairFieldFN Function which returns a field to snap crosshairs to on panel
initializeFN Function called when study first added or edited
inputs Fields used to qualify calculation function
isHighlighted Function to determine if mouse position is in the highlight zone
name Name to be shown in study dialog, menu, or other catalog of studies
outputs Fields used to specify rendering data, along with colors
overlay Indicates study is drawn over an existing panel
panelHeight Specify a height in pixels for a new study panel
parameters Fields used, generally, as inputs to the rendering function
permanent Indicates study cannot be removed by user
range Sets the y-axis max and min values
removeFN Function called on study removal to clean up any resources created by study
seriesFN Function used to render the study
underlay Indicates study is drawn behind the existing panel
yAxis Object containing properties of the y-axis of the study
yAxisFN Function to draw a custom y-axis for the study panel